From patchwork Thu Feb 4 19:43:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068537 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BEC54C433DB for ; Thu, 4 Feb 2021 19:43:48 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4F88064F45 for ; Thu, 4 Feb 2021 19:43:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4F88064F45 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C80B56E0C6; Thu, 4 Feb 2021 19:43:47 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5D8DA6E0C6 for ; Thu, 4 Feb 2021 19:43:46 +0000 (UTC) IronPort-SDR: s/7uOzbpf8s7n7fEw6T/tzrXxx8u3gWlMLgGvzj3OvUAeAon8JaDGInZZmsqr7OseSKeHvWfSt Pkdnc943sKKA== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="245387681" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="245387681" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:43:44 -0800 IronPort-SDR: gSe7ZWzYsuua7qrUFOZ6ywHZu+kWOoWb5ylOwq06eWZm/T7MqEHwX+PafmjXpRuootEaDQqST6 eUdokXAnrbvQ== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="372993129" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:43:39 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:18 +0200 Message-Id: X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 01/10] drm/i915: refactor ddi translations into a separate file (v2) 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie Ville suggested this, these tables are probably better being standalone. This fixes up the cnl/bxt interfaces to be like the others, the intel one I left alone since it has a few extra entrypoints. v2: add back missing rocketlake bits. Reviewed-by: Ville Syrjälä Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 1417 +---------------- .../drm/i915/display/intel_ddi_buf_trans.c | 1394 ++++++++++++++++ .../drm/i915/display/intel_ddi_buf_trans.h | 100 ++ 4 files changed, 1507 insertions(+), 1405 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c create mode 100644 drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index ce01634d4ea7..d571e87416dc 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -243,6 +243,7 @@ i915-y += \ display/icl_dsi.o \ display/intel_crt.o \ display/intel_ddi.o \ + display/intel_ddi_buf_trans.o \ display/intel_dp.o \ display/intel_dp_aux.o \ display/intel_dp_aux_backlight.o \ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 5bc5033a2dea..e2b82e0557e7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -33,6 +33,7 @@ #include "intel_combo_phy.h" #include "intel_connector.h" #include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_mst.h" @@ -53,12 +54,6 @@ #include "intel_vdsc.h" #include "intel_vrr.h" -struct ddi_buf_trans { - u32 trans1; /* balance leg enable, de-emph level */ - u32 trans2; /* vref sel, vswing */ - u8 i_boost; /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */ -}; - static const u8 index_to_dp_signal_levels[] = { [0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0, [1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1, @@ -72,1389 +67,15 @@ static const u8 index_to_dp_signal_levels[] = { [9] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0, }; -/* HDMI/DVI modes ignore everything but the last 2 items. So we share - * them for both DP and FDI transports, allowing those ports to - * automatically adapt to HDMI connections as well - */ -static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0006000E, 0x0 }, - { 0x00D75FFF, 0x0005000A, 0x0 }, - { 0x00C30FFF, 0x00040006, 0x0 }, - { 0x80AAAFFF, 0x000B0000, 0x0 }, - { 0x00FFFFFF, 0x0005000A, 0x0 }, - { 0x00D75FFF, 0x000C0004, 0x0 }, - { 0x80C30FFF, 0x000B0000, 0x0 }, - { 0x00FFFFFF, 0x00040006, 0x0 }, - { 0x80D75FFF, 0x000B0000, 0x0 }, -}; - -static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0007000E, 0x0 }, - { 0x00D75FFF, 0x000F000A, 0x0 }, - { 0x00C30FFF, 0x00060006, 0x0 }, - { 0x00AAAFFF, 0x001E0000, 0x0 }, - { 0x00FFFFFF, 0x000F000A, 0x0 }, - { 0x00D75FFF, 0x00160004, 0x0 }, - { 0x00C30FFF, 0x001E0000, 0x0 }, - { 0x00FFFFFF, 0x00060006, 0x0 }, - { 0x00D75FFF, 0x001E0000, 0x0 }, -}; - -static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { - /* Idx NT mV d T mV d db */ - { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */ - { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */ - { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */ - { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */ - { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */ - { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */ - { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */ - { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */ - { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */ - { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */ - { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */ - { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */ -}; - -static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { - { 0x00FFFFFF, 0x00000012, 0x0 }, - { 0x00EBAFFF, 0x00020011, 0x0 }, - { 0x00C71FFF, 0x0006000F, 0x0 }, - { 0x00AAAFFF, 0x000E000A, 0x0 }, - { 0x00FFFFFF, 0x00020011, 0x0 }, - { 0x00DB6FFF, 0x0005000F, 0x0 }, - { 0x00BEEFFF, 0x000A000C, 0x0 }, - { 0x00FFFFFF, 0x0005000F, 0x0 }, - { 0x00DB6FFF, 0x000A000C, 0x0 }, -}; - -static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0007000E, 0x0 }, - { 0x00D75FFF, 0x000E000A, 0x0 }, - { 0x00BEFFFF, 0x00140006, 0x0 }, - { 0x80B2CFFF, 0x001B0002, 0x0 }, - { 0x00FFFFFF, 0x000E000A, 0x0 }, - { 0x00DB6FFF, 0x00160005, 0x0 }, - { 0x80C71FFF, 0x001A0002, 0x0 }, - { 0x00F7DFFF, 0x00180004, 0x0 }, - { 0x80D75FFF, 0x001B0002, 0x0 }, -}; - -static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0001000E, 0x0 }, - { 0x00D75FFF, 0x0004000A, 0x0 }, - { 0x00C30FFF, 0x00070006, 0x0 }, - { 0x00AAAFFF, 0x000C0000, 0x0 }, - { 0x00FFFFFF, 0x0004000A, 0x0 }, - { 0x00D75FFF, 0x00090004, 0x0 }, - { 0x00C30FFF, 0x000C0000, 0x0 }, - { 0x00FFFFFF, 0x00070006, 0x0 }, - { 0x00D75FFF, 0x000C0000, 0x0 }, -}; - -static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { - /* Idx NT mV d T mV df db */ - { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */ - { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */ - { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */ - { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */ - { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */ - { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */ - { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */ - { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */ - { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */ - { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ -}; - -/* Skylake H and S */ -static const struct ddi_buf_trans skl_ddi_translations_dp[] = { - { 0x00002016, 0x000000A0, 0x0 }, - { 0x00005012, 0x0000009B, 0x0 }, - { 0x00007011, 0x00000088, 0x0 }, - { 0x80009010, 0x000000C0, 0x1 }, - { 0x00002016, 0x0000009B, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000C0, 0x1 }, - { 0x00002016, 0x000000DF, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, -}; - -/* Skylake U */ -static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { - { 0x0000201B, 0x000000A2, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x1 }, - { 0x80009010, 0x000000C0, 0x1 }, - { 0x0000201B, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, - { 0x80007011, 0x000000C0, 0x1 }, - { 0x00002016, 0x00000088, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, -}; - -/* Skylake Y */ -static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = { - { 0x00000018, 0x000000A2, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x3 }, - { 0x80009010, 0x000000C0, 0x3 }, - { 0x00000018, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, - { 0x80007011, 0x000000C0, 0x3 }, - { 0x00000018, 0x00000088, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, -}; - -/* Kabylake H and S */ -static const struct ddi_buf_trans kbl_ddi_translations_dp[] = { - { 0x00002016, 0x000000A0, 0x0 }, - { 0x00005012, 0x0000009B, 0x0 }, - { 0x00007011, 0x00000088, 0x0 }, - { 0x80009010, 0x000000C0, 0x1 }, - { 0x00002016, 0x0000009B, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000C0, 0x1 }, - { 0x00002016, 0x00000097, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, -}; - -/* Kabylake U */ -static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = { - { 0x0000201B, 0x000000A1, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x3 }, - { 0x80009010, 0x000000C0, 0x3 }, - { 0x0000201B, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, - { 0x80007011, 0x000000C0, 0x3 }, - { 0x00002016, 0x0000004F, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, -}; - -/* Kabylake Y */ -static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = { - { 0x00001017, 0x000000A1, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x3 }, - { 0x8000800F, 0x000000C0, 0x3 }, - { 0x00001017, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, - { 0x80007011, 0x000000C0, 0x3 }, - { 0x00001017, 0x0000004C, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, -}; - -/* - * Skylake/Kabylake H and S - * eDP 1.4 low vswing translation parameters - */ -static const struct ddi_buf_trans skl_ddi_translations_edp[] = { - { 0x00000018, 0x000000A8, 0x0 }, - { 0x00004013, 0x000000A9, 0x0 }, - { 0x00007011, 0x000000A2, 0x0 }, - { 0x00009010, 0x0000009C, 0x0 }, - { 0x00000018, 0x000000A9, 0x0 }, - { 0x00006013, 0x000000A2, 0x0 }, - { 0x00007011, 0x000000A6, 0x0 }, - { 0x00000018, 0x000000AB, 0x0 }, - { 0x00007013, 0x0000009F, 0x0 }, - { 0x00000018, 0x000000DF, 0x0 }, -}; - -/* - * Skylake/Kabylake U - * eDP 1.4 low vswing translation parameters - */ -static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { - { 0x00000018, 0x000000A8, 0x0 }, - { 0x00004013, 0x000000A9, 0x0 }, - { 0x00007011, 0x000000A2, 0x0 }, - { 0x00009010, 0x0000009C, 0x0 }, - { 0x00000018, 0x000000A9, 0x0 }, - { 0x00006013, 0x000000A2, 0x0 }, - { 0x00007011, 0x000000A6, 0x0 }, - { 0x00002016, 0x000000AB, 0x0 }, - { 0x00005013, 0x0000009F, 0x0 }, - { 0x00000018, 0x000000DF, 0x0 }, -}; - -/* - * Skylake/Kabylake Y - * eDP 1.4 low vswing translation parameters - */ -static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = { - { 0x00000018, 0x000000A8, 0x0 }, - { 0x00004013, 0x000000AB, 0x0 }, - { 0x00007011, 0x000000A4, 0x0 }, - { 0x00009010, 0x000000DF, 0x0 }, - { 0x00000018, 0x000000AA, 0x0 }, - { 0x00006013, 0x000000A4, 0x0 }, - { 0x00007011, 0x0000009D, 0x0 }, - { 0x00000018, 0x000000A0, 0x0 }, - { 0x00006012, 0x000000DF, 0x0 }, - { 0x00000018, 0x0000008A, 0x0 }, -}; - -/* Skylake/Kabylake U, H and S */ -static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { - { 0x00000018, 0x000000AC, 0x0 }, - { 0x00005012, 0x0000009D, 0x0 }, - { 0x00007011, 0x00000088, 0x0 }, - { 0x00000018, 0x000000A1, 0x0 }, - { 0x00000018, 0x00000098, 0x0 }, - { 0x00004013, 0x00000088, 0x0 }, - { 0x80006012, 0x000000CD, 0x1 }, - { 0x00000018, 0x000000DF, 0x0 }, - { 0x80003015, 0x000000CD, 0x1 }, /* Default */ - { 0x80003015, 0x000000C0, 0x1 }, - { 0x80000018, 0x000000C0, 0x1 }, -}; - -/* Skylake/Kabylake Y */ -static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = { - { 0x00000018, 0x000000A1, 0x0 }, - { 0x00005012, 0x000000DF, 0x0 }, - { 0x80007011, 0x000000CB, 0x3 }, - { 0x00000018, 0x000000A4, 0x0 }, - { 0x00000018, 0x0000009D, 0x0 }, - { 0x00004013, 0x00000080, 0x0 }, - { 0x80006013, 0x000000C0, 0x3 }, - { 0x00000018, 0x0000008A, 0x0 }, - { 0x80003015, 0x000000C0, 0x3 }, /* Default */ - { 0x80003015, 0x000000C0, 0x3 }, - { 0x80000018, 0x000000C0, 0x3 }, -}; - -struct bxt_ddi_buf_trans { - u8 margin; /* swing value */ - u8 scale; /* scale value */ - u8 enable; /* scale enable */ - u8 deemphasis; -}; - -static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { - /* Idx NT mV diff db */ - { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ - { 78, 0x9A, 0, 85, }, /* 1: 400 3.5 */ - { 104, 0x9A, 0, 64, }, /* 2: 400 6 */ - { 154, 0x9A, 0, 43, }, /* 3: 400 9.5 */ - { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ - { 116, 0x9A, 0, 85, }, /* 5: 600 3.5 */ - { 154, 0x9A, 0, 64, }, /* 6: 600 6 */ - { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ - { 154, 0x9A, 0, 85, }, /* 8: 800 3.5 */ - { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ -}; - -static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = { - /* Idx NT mV diff db */ - { 26, 0, 0, 128, }, /* 0: 200 0 */ - { 38, 0, 0, 112, }, /* 1: 200 1.5 */ - { 48, 0, 0, 96, }, /* 2: 200 4 */ - { 54, 0, 0, 69, }, /* 3: 200 6 */ - { 32, 0, 0, 128, }, /* 4: 250 0 */ - { 48, 0, 0, 104, }, /* 5: 250 1.5 */ - { 54, 0, 0, 85, }, /* 6: 250 4 */ - { 43, 0, 0, 128, }, /* 7: 300 0 */ - { 54, 0, 0, 101, }, /* 8: 300 1.5 */ - { 48, 0, 0, 128, }, /* 9: 300 0 */ -}; - -/* BSpec has 2 recommended values - entries 0 and 8. - * Using the entry with higher vswing. - */ -static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { - /* Idx NT mV diff db */ - { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ - { 52, 0x9A, 0, 85, }, /* 1: 400 3.5 */ - { 52, 0x9A, 0, 64, }, /* 2: 400 6 */ - { 42, 0x9A, 0, 43, }, /* 3: 400 9.5 */ - { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ - { 77, 0x9A, 0, 85, }, /* 5: 600 3.5 */ - { 77, 0x9A, 0, 64, }, /* 6: 600 6 */ - { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ - { 102, 0x9A, 0, 85, }, /* 8: 800 3.5 */ - { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ -}; - -struct cnl_ddi_buf_trans { - u8 dw2_swing_sel; - u8 dw7_n_scalar; - u8 dw4_cursor_coeff; - u8 dw4_post_cursor_2; - u8 dw4_post_cursor_1; -}; - -/* Voltage Swing Programming for VccIO 0.85V for DP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_85V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ - { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ - { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ - { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ - { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ - { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.85V for HDMI */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_85V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ - { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ - { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 */ - { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.85V for eDP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_85V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x66, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ - { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ - { 0xA, 0x66, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ - { 0xB, 0x70, 0x3C, 0x00, 0x03 }, /* 460 600 2.3 */ - { 0xC, 0x75, 0x3C, 0x00, 0x03 }, /* 537 700 2.3 */ - { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for DP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_95V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ - { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ - { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ - { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ - { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ - { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for HDMI */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_95V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5C, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ - { 0xB, 0x69, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ - { 0x5, 0x76, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ - { 0xA, 0x5E, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x69, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ - { 0xB, 0x79, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ - { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ - { 0x5, 0x76, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ - { 0x6, 0x7D, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ - { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for eDP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_95V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x61, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ - { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ - { 0xA, 0x61, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ - { 0xB, 0x68, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ - { 0xC, 0x6E, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ - { 0x4, 0x7F, 0x3A, 0x00, 0x05 }, /* 460 600 2.3 */ - { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 1.05V for DP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_1_05V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ - { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ - { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ - { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 400 1050 8.4 */ - { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ - { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 550 1050 5.6 */ - { 0x5, 0x76, 0x3E, 0x00, 0x01 }, /* 850 900 0.5 */ - { 0x6, 0x7F, 0x36, 0x00, 0x09 }, /* 750 1050 2.9 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 1.05V for HDMI */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_1_05V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ - { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ - { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ - { 0xA, 0x5B, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ - { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ - { 0x6, 0x7C, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ - { 0x5, 0x70, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ - { 0x6, 0x7C, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ - { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 1.05V for eDP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5E, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ - { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ - { 0xA, 0x5E, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ - { 0xB, 0x64, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ - { 0xE, 0x6A, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ - { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ -}; - -/* icl_combo_phy_ddi_translations */ -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = { - /* NT mV Trans mV db */ - { 0x0, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ - { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ - { 0x9, 0x7F, 0x31, 0x00, 0x0E }, /* 200 350 4.9 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ - { 0x9, 0x7F, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ - { 0x9, 0x7F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ -}; - -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = { - /* NT mV Trans mV db */ - { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ - { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ - { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 ALS */ - { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ -}; - -static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = { - /* NT mV Trans mV db */ - { 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ - { 0xC, 0x64, 0x34, 0x00, 0x0B }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 350 900 8.2 */ - { 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x64, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ - { 0xC, 0x61, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x38, 0x00, 0x07 }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr[] = { - /* NT mV Trans mV db */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ - { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ - { 0xA, 0x35, 0x36, 0x00, 0x09 }, /* 200 350 4.9 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ - { 0xA, 0x35, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ - { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ -}; - -static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2[] = { - /* NT mV Trans mV db */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 250 1.9 */ - { 0x1, 0x7F, 0x3D, 0x00, 0x02 }, /* 200 300 3.5 */ - { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 200 350 4.9 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 300 1.6 */ - { 0xA, 0x35, 0x3A, 0x00, 0x05 }, /* 250 350 2.9 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ - { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ -}; - -static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_rbr_hbr[] = { - /* NT mV Trans mV db */ - { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ - { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xC, 0x60, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { - /* NT mV Trans mV db */ - { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ - { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xC, 0x58, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -struct icl_mg_phy_ddi_buf_trans { - u32 cri_txdeemph_override_11_6; - u32 cri_txdeemph_override_5_0; - u32 cri_txdeemph_override_17_12; -}; - -static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_rbr_hbr[] = { - /* Voltage swing pre-emphasis */ - { 0x18, 0x00, 0x00 }, /* 0 0 */ - { 0x1D, 0x00, 0x05 }, /* 0 1 */ - { 0x24, 0x00, 0x0C }, /* 0 2 */ - { 0x2B, 0x00, 0x14 }, /* 0 3 */ - { 0x21, 0x00, 0x00 }, /* 1 0 */ - { 0x2B, 0x00, 0x08 }, /* 1 1 */ - { 0x30, 0x00, 0x0F }, /* 1 2 */ - { 0x31, 0x00, 0x03 }, /* 2 0 */ - { 0x34, 0x00, 0x0B }, /* 2 1 */ - { 0x3F, 0x00, 0x00 }, /* 3 0 */ -}; - -static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hbr2_hbr3[] = { - /* Voltage swing pre-emphasis */ - { 0x18, 0x00, 0x00 }, /* 0 0 */ - { 0x1D, 0x00, 0x05 }, /* 0 1 */ - { 0x24, 0x00, 0x0C }, /* 0 2 */ - { 0x2B, 0x00, 0x14 }, /* 0 3 */ - { 0x26, 0x00, 0x00 }, /* 1 0 */ - { 0x2C, 0x00, 0x07 }, /* 1 1 */ - { 0x33, 0x00, 0x0C }, /* 1 2 */ - { 0x2E, 0x00, 0x00 }, /* 2 0 */ - { 0x36, 0x00, 0x09 }, /* 2 1 */ - { 0x3F, 0x00, 0x00 }, /* 3 0 */ -}; - -static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hdmi[] = { - /* HDMI Preset VS Pre-emph */ - { 0x1A, 0x0, 0x0 }, /* 1 400mV 0dB */ - { 0x20, 0x0, 0x0 }, /* 2 500mV 0dB */ - { 0x29, 0x0, 0x0 }, /* 3 650mV 0dB */ - { 0x32, 0x0, 0x0 }, /* 4 800mV 0dB */ - { 0x3F, 0x0, 0x0 }, /* 5 1000mV 0dB */ - { 0x3A, 0x0, 0x5 }, /* 6 Full -1.5 dB */ - { 0x39, 0x0, 0x6 }, /* 7 Full -1.8 dB */ - { 0x38, 0x0, 0x7 }, /* 8 Full -2 dB */ - { 0x37, 0x0, 0x8 }, /* 9 Full -2.5 dB */ - { 0x36, 0x0, 0x9 }, /* 10 Full -3 dB */ -}; - -struct tgl_dkl_phy_ddi_buf_trans { - u32 dkl_vswing_control; - u32 dkl_preshoot_control; - u32 dkl_de_emphasis_control; -}; - -static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans[] = { - /* VS pre-emp Non-trans mV Pre-emph dB */ - { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ - { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ - { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ - { 0x0, 0x0, 0x18 }, /* 0 3 400mV 9.5 dB */ - { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ - { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ - { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ - { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ - { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ - { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ -}; - -static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans_hbr2[] = { - /* VS pre-emp Non-trans mV Pre-emph dB */ - { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ - { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ - { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ - { 0x0, 0x0, 0x19 }, /* 0 3 400mV 9.5 dB */ - { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ - { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ - { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ - { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ - { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ - { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ -}; - -static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_hdmi_ddi_trans[] = { - /* HDMI Preset VS Pre-emph */ - { 0x7, 0x0, 0x0 }, /* 1 400mV 0dB */ - { 0x6, 0x0, 0x0 }, /* 2 500mV 0dB */ - { 0x4, 0x0, 0x0 }, /* 3 650mV 0dB */ - { 0x2, 0x0, 0x0 }, /* 4 800mV 0dB */ - { 0x0, 0x0, 0x0 }, /* 5 1000mV 0dB */ - { 0x0, 0x0, 0x5 }, /* 6 Full -1.5 dB */ - { 0x0, 0x0, 0x6 }, /* 7 Full -1.8 dB */ - { 0x0, 0x0, 0x7 }, /* 8 Full -2 dB */ - { 0x0, 0x0, 0x8 }, /* 9 Full -2.5 dB */ - { 0x0, 0x0, 0xA }, /* 10 Full -3 dB */ -}; - -static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr[] = { - /* NT mV Trans mV db */ - { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7D, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x63, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x61, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7B, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ - { 0xC, 0x60, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ - { 0xC, 0x7F, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ - { 0xC, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x6F, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ - { 0x6, 0x60, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -/* - * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries - * that DisplayPort specification requires - */ -static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = { - /* VS pre-emp */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 0 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 1 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 2 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 3 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 0 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 1 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 2 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 0 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 1 */ -}; - -static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr[] = { - /* NT mV Trans mV db */ - { 0xA, 0x2F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7D, 0x2A, 0x00, 0x15 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6E, 0x3E, 0x00, 0x01 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x50, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ - { 0xC, 0x61, 0x33, 0x00, 0x0C }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2E, 0x00, 0x11 }, /* 350 900 8.2 */ - { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x5F, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x5F, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7E, 0x36, 0x00, 0x09 }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table) -{ - return table == tgl_combo_phy_ddi_translations_edp_hbr2_hobl; -} - -static const struct ddi_buf_trans * -bdw_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp); - return bdw_ddi_translations_edp; - } else { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); - return bdw_ddi_translations_dp; - } -} - -static const struct ddi_buf_trans * -skl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_SKL_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp); - return skl_y_ddi_translations_dp; - } else if (IS_SKL_ULT(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); - return skl_u_ddi_translations_dp; - } else { - *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); - return skl_ddi_translations_dp; - } -} - -static const struct ddi_buf_trans * -kbl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_KBL_ULX(dev_priv) || - IS_CFL_ULX(dev_priv) || - IS_CML_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp); - return kbl_y_ddi_translations_dp; - } else if (IS_KBL_ULT(dev_priv) || - IS_CFL_ULT(dev_priv) || - IS_CML_ULT(dev_priv)) { - *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp); - return kbl_u_ddi_translations_dp; - } else { - *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp); - return kbl_ddi_translations_dp; - } -} - -static const struct ddi_buf_trans * -skl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - if (IS_SKL_ULX(dev_priv) || - IS_KBL_ULX(dev_priv) || - IS_CFL_ULX(dev_priv) || - IS_CML_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp); - return skl_y_ddi_translations_edp; - } else if (IS_SKL_ULT(dev_priv) || - IS_KBL_ULT(dev_priv) || - IS_CFL_ULT(dev_priv) || - IS_CML_ULT(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp); - return skl_u_ddi_translations_edp; - } else { - *n_entries = ARRAY_SIZE(skl_ddi_translations_edp); - return skl_ddi_translations_edp; - } - } - - if (IS_KABYLAKE(dev_priv) || - IS_COFFEELAKE(dev_priv) || - IS_COMETLAKE(dev_priv)) - return kbl_get_buf_trans_dp(encoder, n_entries); - else - return skl_get_buf_trans_dp(encoder, n_entries); -} - -static const struct ddi_buf_trans * -skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries) -{ - if (IS_SKL_ULX(dev_priv) || - IS_KBL_ULX(dev_priv) || - IS_CFL_ULX(dev_priv) || - IS_CML_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi); - return skl_y_ddi_translations_hdmi; - } else { - *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); - return skl_ddi_translations_hdmi; - } -} - -static int skl_buf_trans_num_entries(enum port port, int n_entries) -{ - /* Only DDIA and DDIE can select the 10th register with DP */ - if (port == PORT_A || port == PORT_E) - return min(n_entries, 10); - else - return min(n_entries, 9); -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_KABYLAKE(dev_priv) || - IS_COFFEELAKE(dev_priv) || - IS_COMETLAKE(dev_priv)) { - const struct ddi_buf_trans *ddi_translations = - kbl_get_buf_trans_dp(encoder, n_entries); - *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; - } else if (IS_SKYLAKE(dev_priv)) { - const struct ddi_buf_trans *ddi_translations = - skl_get_buf_trans_dp(encoder, n_entries); - *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; - } else if (IS_BROADWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); - return bdw_ddi_translations_dp; - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); - return hsw_ddi_translations_dp; - } - - *n_entries = 0; - return NULL; -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_GEN9_BC(dev_priv)) { - const struct ddi_buf_trans *ddi_translations = - skl_get_buf_trans_edp(encoder, n_entries); - *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; - } else if (IS_BROADWELL(dev_priv)) { - return bdw_get_buf_trans_edp(encoder, n_entries); - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); - return hsw_ddi_translations_dp; - } - - *n_entries = 0; - return NULL; -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv, - int *n_entries) -{ - if (IS_BROADWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi); - return bdw_ddi_translations_fdi; - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi); - return hsw_ddi_translations_fdi; - } - - *n_entries = 0; - return NULL; -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_GEN9_BC(dev_priv)) { - return skl_get_buf_trans_hdmi(dev_priv, n_entries); - } else if (IS_BROADWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); - return bdw_ddi_translations_hdmi; - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); - return hsw_ddi_translations_hdmi; - } - - *n_entries = 0; - return NULL; -} - -static const struct bxt_ddi_buf_trans * -bxt_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - *n_entries = ARRAY_SIZE(bxt_ddi_translations_dp); - return bxt_ddi_translations_dp; -} - -static const struct bxt_ddi_buf_trans * -bxt_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(bxt_ddi_translations_edp); - return bxt_ddi_translations_edp; - } - - return bxt_get_buf_trans_dp(encoder, n_entries); -} - -static const struct bxt_ddi_buf_trans * -bxt_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) -{ - *n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi); - return bxt_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -cnl_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - - if (voltage == VOLTAGE_INFO_0_85V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V); - return cnl_ddi_translations_hdmi_0_85V; - } else if (voltage == VOLTAGE_INFO_0_95V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V); - return cnl_ddi_translations_hdmi_0_95V; - } else if (voltage == VOLTAGE_INFO_1_05V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V); - return cnl_ddi_translations_hdmi_1_05V; - } else { - *n_entries = 1; /* shut up gcc */ - MISSING_CASE(voltage); - } - return NULL; -} - -static const struct cnl_ddi_buf_trans * -cnl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - - if (voltage == VOLTAGE_INFO_0_85V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V); - return cnl_ddi_translations_dp_0_85V; - } else if (voltage == VOLTAGE_INFO_0_95V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V); - return cnl_ddi_translations_dp_0_95V; - } else if (voltage == VOLTAGE_INFO_1_05V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V); - return cnl_ddi_translations_dp_1_05V; - } else { - *n_entries = 1; /* shut up gcc */ - MISSING_CASE(voltage); - } - return NULL; -} - -static const struct cnl_ddi_buf_trans * -cnl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - - if (dev_priv->vbt.edp.low_vswing) { - if (voltage == VOLTAGE_INFO_0_85V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V); - return cnl_ddi_translations_edp_0_85V; - } else if (voltage == VOLTAGE_INFO_0_95V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V); - return cnl_ddi_translations_edp_0_95V; - } else if (voltage == VOLTAGE_INFO_1_05V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V); - return cnl_ddi_translations_edp_1_05V; - } else { - *n_entries = 1; /* shut up gcc */ - MISSING_CASE(voltage); - } - return NULL; - } else { - return cnl_get_buf_trans_dp(encoder, n_entries); - } -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); - return icl_combo_phy_ddi_translations_dp_hbr2; -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (crtc_state->port_clock > 540000) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); - return icl_combo_phy_ddi_translations_edp_hbr3; - } else if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); - return icl_combo_phy_ddi_translations_edp_hbr2; - } else if (IS_DG1(dev_priv) && crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_hbr2_hbr3); - return dg1_combo_phy_ddi_translations_dp_hbr2_hbr3; - } else if (IS_DG1(dev_priv)) { - *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_rbr_hbr); - return dg1_combo_phy_ddi_translations_dp_rbr_hbr; - } - - return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return icl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct icl_mg_phy_ddi_buf_trans * -icl_get_mg_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi); - return icl_mg_phy_ddi_translations_hdmi; -} - -static const struct icl_mg_phy_ddi_buf_trans * -icl_get_mg_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hbr2_hbr3); - return icl_mg_phy_ddi_translations_hbr2_hbr3; - } else { - *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr); - return icl_mg_phy_ddi_translations_rbr_hbr; - } -} - -static const struct icl_mg_phy_ddi_buf_trans * -icl_get_mg_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return icl_get_mg_buf_trans_hdmi(encoder, crtc_state, n_entries); - else - return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp); - return ehl_combo_phy_ddi_translations_dp; -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); - return icl_combo_phy_ddi_translations_edp_hbr2; - } - - return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return ehl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); - return icl_combo_phy_ddi_translations_dp_hbr2; -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - if (crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr2); - return jsl_combo_phy_ddi_translations_edp_hbr2; - } else { - *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr); - return jsl_combo_phy_ddi_translations_edp_hbr; - } - } - - return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return jsl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (crtc_state->port_clock > 270000) { - if (IS_ROCKETLAKE(dev_priv)) { - *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr2_hbr3); - return rkl_combo_phy_ddi_translations_dp_hbr2_hbr3; - } else if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { - *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2); - return tgl_uy_combo_phy_ddi_translations_dp_hbr2; - } else { - *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2); - return tgl_combo_phy_ddi_translations_dp_hbr2; - } - } else { - if (IS_ROCKETLAKE(dev_priv)) { - *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr); - return rkl_combo_phy_ddi_translations_dp_hbr; - } else { - *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr); - return tgl_combo_phy_ddi_translations_dp_hbr; - } - } -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - if (crtc_state->port_clock > 540000) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); - return icl_combo_phy_ddi_translations_edp_hbr3; - } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { - *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl); - return tgl_combo_phy_ddi_translations_edp_hbr2_hobl; - } else if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); - return icl_combo_phy_ddi_translations_edp_hbr2; - } - - return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct tgl_dkl_phy_ddi_buf_trans * -tgl_get_dkl_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans); - return tgl_dkl_phy_hdmi_ddi_trans; -} - -static const struct tgl_dkl_phy_ddi_buf_trans * -tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans_hbr2); - return tgl_dkl_phy_dp_ddi_trans_hbr2; - } else { - *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans); - return tgl_dkl_phy_dp_ddi_trans; - } -} - -static const struct tgl_dkl_phy_ddi_buf_trans * -tgl_get_dkl_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, n_entries); - else - return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries); -} - static int intel_ddi_hdmi_level(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); int n_entries, level, default_entry; - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - if (INTEL_GEN(dev_priv) >= 12) { - if (intel_phy_is_combo(dev_priv, phy)) - tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); - else - tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries); - default_entry = n_entries - 1; - } else if (INTEL_GEN(dev_priv) == 11) { - if (intel_phy_is_combo(dev_priv, phy)) - icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); - else - icl_get_mg_buf_trans_hdmi(encoder, crtc_state, &n_entries); - default_entry = n_entries - 1; - } else if (IS_CANNONLAKE(dev_priv)) { - cnl_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = n_entries - 1; - } else if (IS_GEN9_LP(dev_priv)) { - bxt_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = n_entries - 1; - } else if (IS_GEN9_BC(dev_priv)) { - intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = 8; - } else if (IS_BROADWELL(dev_priv)) { - intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = 7; - } else if (IS_HASWELL(dev_priv)) { - intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = 6; - } else { - drm_WARN(&dev_priv->drm, 1, "ddi translation table missing\n"); + n_entries = intel_ddi_hdmi_num_entries(encoder, crtc_state, &default_entry); + if (n_entries == 0) return 0; - } - - if (drm_WARN_ON_ONCE(&dev_priv->drm, n_entries == 0)) - return 0; - level = intel_bios_hdmi_level_shift(encoder); if (level < 0) level = default_entry; @@ -1637,6 +258,9 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 temp, i, rx_ctl_val, ddi_pll_sel; + int n_entries; + + intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); intel_prepare_dp_ddi_buffers(encoder, crtc_state); @@ -1669,7 +293,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, /* Start the training iterating through available voltages and emphasis, * testing each value twice. */ - for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) { + for (i = 0; i < n_entries * 2; i++) { /* Configure DP_TP_CTL with auto-training */ intel_de_write(dev_priv, DP_TP_CTL(PORT_E), DP_TP_CTL_FDI_AUTOTRAIN | @@ -1718,7 +342,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, * Leave things enabled even if we failed to train FDI. * Results in less fireworks from the state checker. */ - if (i == ARRAY_SIZE(hsw_ddi_translations_fdi) * 2 - 1) { + if (i == n_entries * 2 - 1) { drm_err(&dev_priv->drm, "FDI link training failed!\n"); break; } @@ -2480,13 +1104,7 @@ static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder, enum port port = encoder->port; int n_entries; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - ddi_translations = bxt_get_buf_trans_hdmi(encoder, &n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - ddi_translations = bxt_get_buf_trans_edp(encoder, &n_entries); - else - ddi_translations = bxt_get_buf_trans_dp(encoder, &n_entries); - + ddi_translations = bxt_get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) @@ -2523,15 +1141,9 @@ static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp, else icl_get_mg_buf_trans(encoder, crtc_state, &n_entries); } else if (IS_CANNONLAKE(dev_priv)) { - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - cnl_get_buf_trans_edp(encoder, &n_entries); - else - cnl_get_buf_trans_dp(encoder, &n_entries); + cnl_get_buf_trans(encoder, crtc_state, &n_entries); } else if (IS_GEN9_LP(dev_priv)) { - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - bxt_get_buf_trans_edp(encoder, &n_entries); - else - bxt_get_buf_trans_dp(encoder, &n_entries); + bxt_get_buf_trans(encoder, crtc_state, &n_entries); } else { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) intel_ddi_get_buf_trans_edp(encoder, &n_entries); @@ -2569,12 +1181,7 @@ static void cnl_ddi_vswing_program(struct intel_encoder *encoder, int n_entries, ln; u32 val; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - ddi_translations = cnl_get_buf_trans_hdmi(encoder, &n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - ddi_translations = cnl_get_buf_trans_edp(encoder, &n_entries); - else - ddi_translations = cnl_get_buf_trans_dp(encoder, &n_entries); + ddi_translations = cnl_get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) return; diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c new file mode 100644 index 000000000000..0b00b31dbe59 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -0,0 +1,1394 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ + +#include "i915_drv.h" +#include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" +#include "intel_display_types.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 + * automatically adapt to HDMI connections as well + */ +static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { + { 0x00FFFFFF, 0x0006000E, 0x0 }, + { 0x00D75FFF, 0x0005000A, 0x0 }, + { 0x00C30FFF, 0x00040006, 0x0 }, + { 0x80AAAFFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x0005000A, 0x0 }, + { 0x00D75FFF, 0x000C0004, 0x0 }, + { 0x80C30FFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x00040006, 0x0 }, + { 0x80D75FFF, 0x000B0000, 0x0 }, +}; + +static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000F000A, 0x0 }, + { 0x00C30FFF, 0x00060006, 0x0 }, + { 0x00AAAFFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x000F000A, 0x0 }, + { 0x00D75FFF, 0x00160004, 0x0 }, + { 0x00C30FFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x00060006, 0x0 }, + { 0x00D75FFF, 0x001E0000, 0x0 }, +}; + +static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { + /* Idx NT mV d T mV d db */ + { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */ + { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */ + { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */ + { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */ + { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */ + { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */ + { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */ + { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */ + { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */ + { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */ + { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */ + { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */ +}; + +static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { + { 0x00FFFFFF, 0x00000012, 0x0 }, + { 0x00EBAFFF, 0x00020011, 0x0 }, + { 0x00C71FFF, 0x0006000F, 0x0 }, + { 0x00AAAFFF, 0x000E000A, 0x0 }, + { 0x00FFFFFF, 0x00020011, 0x0 }, + { 0x00DB6FFF, 0x0005000F, 0x0 }, + { 0x00BEEFFF, 0x000A000C, 0x0 }, + { 0x00FFFFFF, 0x0005000F, 0x0 }, + { 0x00DB6FFF, 0x000A000C, 0x0 }, +}; + +static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000E000A, 0x0 }, + { 0x00BEFFFF, 0x00140006, 0x0 }, + { 0x80B2CFFF, 0x001B0002, 0x0 }, + { 0x00FFFFFF, 0x000E000A, 0x0 }, + { 0x00DB6FFF, 0x00160005, 0x0 }, + { 0x80C71FFF, 0x001A0002, 0x0 }, + { 0x00F7DFFF, 0x00180004, 0x0 }, + { 0x80D75FFF, 0x001B0002, 0x0 }, +}; + +static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { + { 0x00FFFFFF, 0x0001000E, 0x0 }, + { 0x00D75FFF, 0x0004000A, 0x0 }, + { 0x00C30FFF, 0x00070006, 0x0 }, + { 0x00AAAFFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x0004000A, 0x0 }, + { 0x00D75FFF, 0x00090004, 0x0 }, + { 0x00C30FFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x00070006, 0x0 }, + { 0x00D75FFF, 0x000C0000, 0x0 }, +}; + +static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { + /* Idx NT mV d T mV df db */ + { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */ + { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */ + { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */ + { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */ + { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */ + { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */ + { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */ + { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */ + { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */ + { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ +}; + +/* Skylake H and S */ +static const struct ddi_buf_trans skl_ddi_translations_dp[] = { + { 0x00002016, 0x000000A0, 0x0 }, + { 0x00005012, 0x0000009B, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x80009010, 0x000000C0, 0x1 }, + { 0x00002016, 0x0000009B, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000C0, 0x1 }, + { 0x00002016, 0x000000DF, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, +}; + +/* Skylake U */ +static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { + { 0x0000201B, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x1 }, + { 0x80009010, 0x000000C0, 0x1 }, + { 0x0000201B, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, + { 0x80007011, 0x000000C0, 0x1 }, + { 0x00002016, 0x00000088, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, +}; + +/* Skylake Y */ +static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = { + { 0x00000018, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x3 }, + { 0x80009010, 0x000000C0, 0x3 }, + { 0x00000018, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, + { 0x80007011, 0x000000C0, 0x3 }, + { 0x00000018, 0x00000088, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, +}; + +/* Kabylake H and S */ +static const struct ddi_buf_trans kbl_ddi_translations_dp[] = { + { 0x00002016, 0x000000A0, 0x0 }, + { 0x00005012, 0x0000009B, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x80009010, 0x000000C0, 0x1 }, + { 0x00002016, 0x0000009B, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000C0, 0x1 }, + { 0x00002016, 0x00000097, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, +}; + +/* Kabylake U */ +static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = { + { 0x0000201B, 0x000000A1, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x3 }, + { 0x80009010, 0x000000C0, 0x3 }, + { 0x0000201B, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, + { 0x80007011, 0x000000C0, 0x3 }, + { 0x00002016, 0x0000004F, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, +}; + +/* Kabylake Y */ +static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = { + { 0x00001017, 0x000000A1, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x3 }, + { 0x8000800F, 0x000000C0, 0x3 }, + { 0x00001017, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, + { 0x80007011, 0x000000C0, 0x3 }, + { 0x00001017, 0x0000004C, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, +}; + +/* + * Skylake/Kabylake H and S + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00000018, 0x000000AB, 0x0 }, + { 0x00007013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, +}; + +/* + * Skylake/Kabylake U + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00002016, 0x000000AB, 0x0 }, + { 0x00005013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, +}; + +/* + * Skylake/Kabylake Y + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000AB, 0x0 }, + { 0x00007011, 0x000000A4, 0x0 }, + { 0x00009010, 0x000000DF, 0x0 }, + { 0x00000018, 0x000000AA, 0x0 }, + { 0x00006013, 0x000000A4, 0x0 }, + { 0x00007011, 0x0000009D, 0x0 }, + { 0x00000018, 0x000000A0, 0x0 }, + { 0x00006012, 0x000000DF, 0x0 }, + { 0x00000018, 0x0000008A, 0x0 }, +}; + +/* Skylake/Kabylake U, H and S */ +static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { + { 0x00000018, 0x000000AC, 0x0 }, + { 0x00005012, 0x0000009D, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00000018, 0x00000098, 0x0 }, + { 0x00004013, 0x00000088, 0x0 }, + { 0x80006012, 0x000000CD, 0x1 }, + { 0x00000018, 0x000000DF, 0x0 }, + { 0x80003015, 0x000000CD, 0x1 }, /* Default */ + { 0x80003015, 0x000000C0, 0x1 }, + { 0x80000018, 0x000000C0, 0x1 }, +}; + +/* Skylake/Kabylake Y */ +static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = { + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00005012, 0x000000DF, 0x0 }, + { 0x80007011, 0x000000CB, 0x3 }, + { 0x00000018, 0x000000A4, 0x0 }, + { 0x00000018, 0x0000009D, 0x0 }, + { 0x00004013, 0x00000080, 0x0 }, + { 0x80006013, 0x000000C0, 0x3 }, + { 0x00000018, 0x0000008A, 0x0 }, + { 0x80003015, 0x000000C0, 0x3 }, /* Default */ + { 0x80003015, 0x000000C0, 0x3 }, + { 0x80000018, 0x000000C0, 0x3 }, +}; + + +static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { + /* Idx NT mV diff db */ + { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ + { 78, 0x9A, 0, 85, }, /* 1: 400 3.5 */ + { 104, 0x9A, 0, 64, }, /* 2: 400 6 */ + { 154, 0x9A, 0, 43, }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ + { 116, 0x9A, 0, 85, }, /* 5: 600 3.5 */ + { 154, 0x9A, 0, 64, }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ + { 154, 0x9A, 0, 85, }, /* 8: 800 3.5 */ + { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ +}; + +static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = { + /* Idx NT mV diff db */ + { 26, 0, 0, 128, }, /* 0: 200 0 */ + { 38, 0, 0, 112, }, /* 1: 200 1.5 */ + { 48, 0, 0, 96, }, /* 2: 200 4 */ + { 54, 0, 0, 69, }, /* 3: 200 6 */ + { 32, 0, 0, 128, }, /* 4: 250 0 */ + { 48, 0, 0, 104, }, /* 5: 250 1.5 */ + { 54, 0, 0, 85, }, /* 6: 250 4 */ + { 43, 0, 0, 128, }, /* 7: 300 0 */ + { 54, 0, 0, 101, }, /* 8: 300 1.5 */ + { 48, 0, 0, 128, }, /* 9: 300 0 */ +}; + +/* BSpec has 2 recommended values - entries 0 and 8. + * Using the entry with higher vswing. + */ +static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { + /* Idx NT mV diff db */ + { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ + { 52, 0x9A, 0, 85, }, /* 1: 400 3.5 */ + { 52, 0x9A, 0, 64, }, /* 2: 400 6 */ + { 42, 0x9A, 0, 43, }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ + { 77, 0x9A, 0, 85, }, /* 5: 600 3.5 */ + { 77, 0x9A, 0, 64, }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ + { 102, 0x9A, 0, 85, }, /* 8: 800 3.5 */ + { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ +}; + +/* Voltage Swing Programming for VccIO 0.85V for DP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_85V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ + { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ + { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.85V for HDMI */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_85V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ + { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ + { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.85V for eDP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_85V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x66, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ + { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ + { 0xA, 0x66, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ + { 0xB, 0x70, 0x3C, 0x00, 0x03 }, /* 460 600 2.3 */ + { 0xC, 0x75, 0x3C, 0x00, 0x03 }, /* 537 700 2.3 */ + { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for DP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_95V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ + { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ + { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for HDMI */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_95V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5C, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ + { 0xB, 0x69, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ + { 0x5, 0x76, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ + { 0xA, 0x5E, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x69, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ + { 0xB, 0x79, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ + { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ + { 0x5, 0x76, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ + { 0x6, 0x7D, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ + { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for eDP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_95V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x61, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ + { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ + { 0xA, 0x61, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ + { 0xB, 0x68, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ + { 0xC, 0x6E, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ + { 0x4, 0x7F, 0x3A, 0x00, 0x05 }, /* 460 600 2.3 */ + { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for DP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_1_05V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ + { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ + { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ + { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 400 1050 8.4 */ + { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ + { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 550 1050 5.6 */ + { 0x5, 0x76, 0x3E, 0x00, 0x01 }, /* 850 900 0.5 */ + { 0x6, 0x7F, 0x36, 0x00, 0x09 }, /* 750 1050 2.9 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for HDMI */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_1_05V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ + { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ + { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ + { 0xA, 0x5B, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ + { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ + { 0x6, 0x7C, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ + { 0x5, 0x70, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ + { 0x6, 0x7C, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ + { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for eDP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5E, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ + { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ + { 0xA, 0x5E, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ + { 0xB, 0x64, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ + { 0xE, 0x6A, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ + { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ +}; + +/* icl_combo_phy_ddi_translations */ +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = { + /* NT mV Trans mV db */ + { 0x0, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ + { 0x9, 0x7F, 0x31, 0x00, 0x0E }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ + { 0x9, 0x7F, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0x9, 0x7F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ +}; + +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = { + /* NT mV Trans mV db */ + { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ + { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ + { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 ALS */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ +}; + +static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = { + /* NT mV Trans mV db */ + { 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ + { 0xC, 0x64, 0x34, 0x00, 0x0B }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 350 900 8.2 */ + { 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x64, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ + { 0xC, 0x61, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x38, 0x00, 0x07 }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr[] = { + /* NT mV Trans mV db */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ + { 0xA, 0x35, 0x36, 0x00, 0x09 }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ + { 0xA, 0x35, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ +}; + +static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2[] = { + /* NT mV Trans mV db */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x3D, 0x00, 0x02 }, /* 200 300 3.5 */ + { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 300 1.6 */ + { 0xA, 0x35, 0x3A, 0x00, 0x05 }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ +}; + +static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_rbr_hbr[] = { + /* NT mV Trans mV db */ + { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ + { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xC, 0x60, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ + { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xC, 0x58, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_rbr_hbr[] = { + /* Voltage swing pre-emphasis */ + { 0x18, 0x00, 0x00 }, /* 0 0 */ + { 0x1D, 0x00, 0x05 }, /* 0 1 */ + { 0x24, 0x00, 0x0C }, /* 0 2 */ + { 0x2B, 0x00, 0x14 }, /* 0 3 */ + { 0x21, 0x00, 0x00 }, /* 1 0 */ + { 0x2B, 0x00, 0x08 }, /* 1 1 */ + { 0x30, 0x00, 0x0F }, /* 1 2 */ + { 0x31, 0x00, 0x03 }, /* 2 0 */ + { 0x34, 0x00, 0x0B }, /* 2 1 */ + { 0x3F, 0x00, 0x00 }, /* 3 0 */ +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hbr2_hbr3[] = { + /* Voltage swing pre-emphasis */ + { 0x18, 0x00, 0x00 }, /* 0 0 */ + { 0x1D, 0x00, 0x05 }, /* 0 1 */ + { 0x24, 0x00, 0x0C }, /* 0 2 */ + { 0x2B, 0x00, 0x14 }, /* 0 3 */ + { 0x26, 0x00, 0x00 }, /* 1 0 */ + { 0x2C, 0x00, 0x07 }, /* 1 1 */ + { 0x33, 0x00, 0x0C }, /* 1 2 */ + { 0x2E, 0x00, 0x00 }, /* 2 0 */ + { 0x36, 0x00, 0x09 }, /* 2 1 */ + { 0x3F, 0x00, 0x00 }, /* 3 0 */ +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hdmi[] = { + /* HDMI Preset VS Pre-emph */ + { 0x1A, 0x0, 0x0 }, /* 1 400mV 0dB */ + { 0x20, 0x0, 0x0 }, /* 2 500mV 0dB */ + { 0x29, 0x0, 0x0 }, /* 3 650mV 0dB */ + { 0x32, 0x0, 0x0 }, /* 4 800mV 0dB */ + { 0x3F, 0x0, 0x0 }, /* 5 1000mV 0dB */ + { 0x3A, 0x0, 0x5 }, /* 6 Full -1.5 dB */ + { 0x39, 0x0, 0x6 }, /* 7 Full -1.8 dB */ + { 0x38, 0x0, 0x7 }, /* 8 Full -2 dB */ + { 0x37, 0x0, 0x8 }, /* 9 Full -2.5 dB */ + { 0x36, 0x0, 0x9 }, /* 10 Full -3 dB */ +}; + +static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans[] = { + /* VS pre-emp Non-trans mV Pre-emph dB */ + { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ + { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ + { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ + { 0x0, 0x0, 0x18 }, /* 0 3 400mV 9.5 dB */ + { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ + { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ + { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ + { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ + { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ + { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ +}; + +static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans_hbr2[] = { + /* VS pre-emp Non-trans mV Pre-emph dB */ + { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ + { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ + { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ + { 0x0, 0x0, 0x19 }, /* 0 3 400mV 9.5 dB */ + { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ + { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ + { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ + { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ + { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ + { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ +}; + +static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_hdmi_ddi_trans[] = { + /* HDMI Preset VS Pre-emph */ + { 0x7, 0x0, 0x0 }, /* 1 400mV 0dB */ + { 0x6, 0x0, 0x0 }, /* 2 500mV 0dB */ + { 0x4, 0x0, 0x0 }, /* 3 650mV 0dB */ + { 0x2, 0x0, 0x0 }, /* 4 800mV 0dB */ + { 0x0, 0x0, 0x0 }, /* 5 1000mV 0dB */ + { 0x0, 0x0, 0x5 }, /* 6 Full -1.5 dB */ + { 0x0, 0x0, 0x6 }, /* 7 Full -1.8 dB */ + { 0x0, 0x0, 0x7 }, /* 8 Full -2 dB */ + { 0x0, 0x0, 0x8 }, /* 9 Full -2.5 dB */ + { 0x0, 0x0, 0xA }, /* 10 Full -3 dB */ +}; + +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr[] = { + /* NT mV Trans mV db */ + { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7D, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x63, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x61, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7B, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ + { 0xC, 0x60, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0xC, 0x7F, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xC, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x6F, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ + { 0x6, 0x60, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* + * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries + * that DisplayPort specification requires + */ +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = { + /* VS pre-emp */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 1 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 2 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 1 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 2 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 1 */ +}; + +static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr[] = { + /* NT mV Trans mV db */ + { 0xA, 0x2F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7D, 0x2A, 0x00, 0x15 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6E, 0x3E, 0x00, 0x01 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x50, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ + { 0xC, 0x61, 0x33, 0x00, 0x0C }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2E, 0x00, 0x11 }, /* 350 900 8.2 */ + { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x5F, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x5F, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7E, 0x36, 0x00, 0x09 }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table) +{ + return table == tgl_combo_phy_ddi_translations_edp_hbr2_hobl; +} + +const struct ddi_buf_trans * +bdw_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp); + return bdw_ddi_translations_edp; + } else { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); + return bdw_ddi_translations_dp; + } +} + +const struct ddi_buf_trans * +skl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_SKL_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp); + return skl_y_ddi_translations_dp; + } else if (IS_SKL_ULT(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); + return skl_u_ddi_translations_dp; + } else { + *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); + return skl_ddi_translations_dp; + } +} + +const struct ddi_buf_trans * +kbl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_KBL_ULX(dev_priv) || + IS_CFL_ULX(dev_priv) || + IS_CML_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp); + return kbl_y_ddi_translations_dp; + } else if (IS_KBL_ULT(dev_priv) || + IS_CFL_ULT(dev_priv) || + IS_CML_ULT(dev_priv)) { + *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp); + return kbl_u_ddi_translations_dp; + } else { + *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp); + return kbl_ddi_translations_dp; + } +} + +const struct ddi_buf_trans * +skl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + if (IS_SKL_ULX(dev_priv) || + IS_KBL_ULX(dev_priv) || + IS_CFL_ULX(dev_priv) || + IS_CML_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp); + return skl_y_ddi_translations_edp; + } else if (IS_SKL_ULT(dev_priv) || + IS_KBL_ULT(dev_priv) || + IS_CFL_ULT(dev_priv) || + IS_CML_ULT(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp); + return skl_u_ddi_translations_edp; + } else { + *n_entries = ARRAY_SIZE(skl_ddi_translations_edp); + return skl_ddi_translations_edp; + } + } + + if (IS_KABYLAKE(dev_priv) || + IS_COFFEELAKE(dev_priv) || + IS_COMETLAKE(dev_priv)) + return kbl_get_buf_trans_dp(encoder, n_entries); + else + return skl_get_buf_trans_dp(encoder, n_entries); +} + +const struct ddi_buf_trans * +skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries) +{ + if (IS_SKL_ULX(dev_priv) || + IS_KBL_ULX(dev_priv) || + IS_CFL_ULX(dev_priv) || + IS_CML_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi); + return skl_y_ddi_translations_hdmi; + } else { + *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); + return skl_ddi_translations_hdmi; + } +} + +int skl_buf_trans_num_entries(enum port port, int n_entries) +{ + /* Only DDIA and DDIE can select the 10th register with DP */ + if (port == PORT_A || port == PORT_E) + return min(n_entries, 10); + else + return min(n_entries, 9); +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_KABYLAKE(dev_priv) || + IS_COFFEELAKE(dev_priv) || + IS_COMETLAKE(dev_priv)) { + const struct ddi_buf_trans *ddi_translations = + kbl_get_buf_trans_dp(encoder, n_entries); + *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); + return ddi_translations; + } else if (IS_SKYLAKE(dev_priv)) { + const struct ddi_buf_trans *ddi_translations = + skl_get_buf_trans_dp(encoder, n_entries); + *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); + return ddi_translations; + } else if (IS_BROADWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); + return bdw_ddi_translations_dp; + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); + return hsw_ddi_translations_dp; + } + + *n_entries = 0; + return NULL; +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_GEN9_BC(dev_priv)) { + const struct ddi_buf_trans *ddi_translations = + skl_get_buf_trans_edp(encoder, n_entries); + *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); + return ddi_translations; + } else if (IS_BROADWELL(dev_priv)) { + return bdw_get_buf_trans_edp(encoder, n_entries); + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); + return hsw_ddi_translations_dp; + } + + *n_entries = 0; + return NULL; +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv, + int *n_entries) +{ + if (IS_BROADWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi); + return bdw_ddi_translations_fdi; + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi); + return hsw_ddi_translations_fdi; + } + + *n_entries = 0; + return NULL; +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_GEN9_BC(dev_priv)) { + return skl_get_buf_trans_hdmi(dev_priv, n_entries); + } else if (IS_BROADWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); + return bdw_ddi_translations_hdmi; + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); + return hsw_ddi_translations_hdmi; + } + + *n_entries = 0; + return NULL; +} + +static const struct bxt_ddi_buf_trans * +bxt_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + *n_entries = ARRAY_SIZE(bxt_ddi_translations_dp); + return bxt_ddi_translations_dp; +} + +static const struct bxt_ddi_buf_trans * +bxt_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(bxt_ddi_translations_edp); + return bxt_ddi_translations_edp; + } + + return bxt_get_buf_trans_dp(encoder, n_entries); +} + +static const struct bxt_ddi_buf_trans * +bxt_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) +{ + *n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi); + return bxt_ddi_translations_hdmi; +} + +const struct bxt_ddi_buf_trans * +bxt_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return bxt_get_buf_trans_hdmi(encoder, n_entries); + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return bxt_get_buf_trans_edp(encoder, n_entries); + return bxt_get_buf_trans_dp(encoder, n_entries); +} + +static const struct cnl_ddi_buf_trans * +cnl_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + if (voltage == VOLTAGE_INFO_0_85V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V); + return cnl_ddi_translations_hdmi_0_85V; + } else if (voltage == VOLTAGE_INFO_0_95V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V); + return cnl_ddi_translations_hdmi_0_95V; + } else if (voltage == VOLTAGE_INFO_1_05V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V); + return cnl_ddi_translations_hdmi_1_05V; + } else { + *n_entries = 1; /* shut up gcc */ + MISSING_CASE(voltage); + } + return NULL; +} + +static const struct cnl_ddi_buf_trans * +cnl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + if (voltage == VOLTAGE_INFO_0_85V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V); + return cnl_ddi_translations_dp_0_85V; + } else if (voltage == VOLTAGE_INFO_0_95V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V); + return cnl_ddi_translations_dp_0_95V; + } else if (voltage == VOLTAGE_INFO_1_05V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V); + return cnl_ddi_translations_dp_1_05V; + } else { + *n_entries = 1; /* shut up gcc */ + MISSING_CASE(voltage); + } + return NULL; +} + +static const struct cnl_ddi_buf_trans * +cnl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + if (dev_priv->vbt.edp.low_vswing) { + if (voltage == VOLTAGE_INFO_0_85V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V); + return cnl_ddi_translations_edp_0_85V; + } else if (voltage == VOLTAGE_INFO_0_95V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V); + return cnl_ddi_translations_edp_0_95V; + } else if (voltage == VOLTAGE_INFO_1_05V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V); + return cnl_ddi_translations_edp_1_05V; + } else { + *n_entries = 1; /* shut up gcc */ + MISSING_CASE(voltage); + } + return NULL; + } else { + return cnl_get_buf_trans_dp(encoder, n_entries); + } +} + +const struct cnl_ddi_buf_trans * +cnl_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return cnl_get_buf_trans_hdmi(encoder, n_entries); + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return cnl_get_buf_trans_edp(encoder, n_entries); + return cnl_get_buf_trans_dp(encoder, n_entries); +} + +static const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); + return icl_combo_phy_ddi_translations_dp_hbr2; +} + +static const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (crtc_state->port_clock > 540000) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); + return icl_combo_phy_ddi_translations_edp_hbr3; + } else if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; + } else if (IS_DG1(dev_priv) && crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_hbr2_hbr3); + return dg1_combo_phy_ddi_translations_dp_hbr2_hbr3; + } else if (IS_DG1(dev_priv)) { + *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_rbr_hbr); + return dg1_combo_phy_ddi_translations_dp_rbr_hbr; + } + + return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return icl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi); + return icl_mg_phy_ddi_translations_hdmi; +} + +static const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hbr2_hbr3); + return icl_mg_phy_ddi_translations_hbr2_hbr3; + } else { + *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr); + return icl_mg_phy_ddi_translations_rbr_hbr; + } +} + +const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return icl_get_mg_buf_trans_hdmi(encoder, crtc_state, n_entries); + else + return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp); + return ehl_combo_phy_ddi_translations_dp; +} + +static const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; + } + + return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return ehl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); + return icl_combo_phy_ddi_translations_dp_hbr2; +} + +static const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + if (crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr2); + return jsl_combo_phy_ddi_translations_edp_hbr2; + } else { + *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr); + return jsl_combo_phy_ddi_translations_edp_hbr; + } + } + + return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return jsl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (crtc_state->port_clock > 270000) { + if (IS_ROCKETLAKE(dev_priv)) { + *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr2_hbr3); + return rkl_combo_phy_ddi_translations_dp_hbr2_hbr3; + } else if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { + *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2); + return tgl_uy_combo_phy_ddi_translations_dp_hbr2; + } else { + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2); + return tgl_combo_phy_ddi_translations_dp_hbr2; + } + } else { + if (IS_ROCKETLAKE(dev_priv)) { + *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr); + return rkl_combo_phy_ddi_translations_dp_hbr; + } else { + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr); + return tgl_combo_phy_ddi_translations_dp_hbr; + } + } +} + +static const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (crtc_state->port_clock > 540000) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); + return icl_combo_phy_ddi_translations_edp_hbr3; + } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl); + return tgl_combo_phy_ddi_translations_edp_hbr2_hobl; + } else if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; + } + + return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans); + return tgl_dkl_phy_hdmi_ddi_trans; +} + +static const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans_hbr2); + return tgl_dkl_phy_dp_ddi_trans_hbr2; + } else { + *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans); + return tgl_dkl_phy_dp_ddi_trans; + } +} + +const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, n_entries); + else + return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries); +} + +int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *default_entry) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + int n_entries; + + if (INTEL_GEN(dev_priv) >= 12) { + if (intel_phy_is_combo(dev_priv, phy)) + tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); + else + tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries); + *default_entry = n_entries - 1; + } else if (INTEL_GEN(dev_priv) == 11) { + if (intel_phy_is_combo(dev_priv, phy)) + icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); + else + icl_get_mg_buf_trans_hdmi(encoder, crtc_state, &n_entries); + *default_entry = n_entries - 1; + } else if (IS_CANNONLAKE(dev_priv)) { + cnl_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = n_entries - 1; + } else if (IS_GEN9_LP(dev_priv)) { + bxt_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = n_entries - 1; + } else if (IS_GEN9_BC(dev_priv)) { + intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = 8; + } else if (IS_BROADWELL(dev_priv)) { + intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = 7; + } else if (IS_HASWELL(dev_priv)) { + intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = 6; + } else { + drm_WARN(&dev_priv->drm, 1, "ddi translation table missing\n"); + return 0; + } + + if (drm_WARN_ON_ONCE(&dev_priv->drm, n_entries == 0)) + return 0; + + return n_entries; +} diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h new file mode 100644 index 000000000000..f8f0ef87e977 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ + +#ifndef _INTEL_DDI_BUF_TRANS_H_ +#define _INTEL_DDI_BUF_TRANS_H_ + +#include + +struct drm_i915_private; +struct intel_encoder; +struct intel_crtc_state; + +struct ddi_buf_trans { + u32 trans1; /* balance leg enable, de-emph level */ + u32 trans2; /* vref sel, vswing */ + u8 i_boost; /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */ +}; + +struct bxt_ddi_buf_trans { + u8 margin; /* swing value */ + u8 scale; /* scale value */ + u8 enable; /* scale enable */ + u8 deemphasis; +}; + +struct cnl_ddi_buf_trans { + u8 dw2_swing_sel; + u8 dw7_n_scalar; + u8 dw4_cursor_coeff; + u8 dw4_post_cursor_2; + u8 dw4_post_cursor_1; +}; + +struct icl_mg_phy_ddi_buf_trans { + u32 cri_txdeemph_override_11_6; + u32 cri_txdeemph_override_5_0; + u32 cri_txdeemph_override_17_12; +}; + +struct tgl_dkl_phy_ddi_buf_trans { + u32 dkl_vswing_control; + u32 dkl_preshoot_control; + u32 dkl_de_emphasis_control; +}; + +bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table); + +int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *default_entry); + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries); +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv, + int *n_entries); +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, + int *n_entries); +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries); + +const struct bxt_ddi_buf_trans * +bxt_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); + +const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); + +const struct cnl_ddi_buf_trans * +cnl_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); + +#endif From patchwork Thu Feb 4 19:43:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068539 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EAD66C433E6 for ; Thu, 4 Feb 2021 19:43:54 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9D9B164F45 for ; Thu, 4 Feb 2021 19:43:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9D9B164F45 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 25F3B6EE47; Thu, 4 Feb 2021 19:43:54 +0000 (UTC) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by gabe.freedesktop.org (Postfix) with ESMTPS id 414F76EE47 for ; Thu, 4 Feb 2021 19:43:53 +0000 (UTC) IronPort-SDR: 41rppSGooHMRQKjeXyYnn4dQBRMermvX52ZdVEOrXwdQktuOMj2Bc4EpbnFL4CXtS1d/kcjq0X 8by0ho9KoLZg== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="242821532" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="242821532" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:43:52 -0800 IronPort-SDR: Sa03UMQYGjjvJAOl4k6rvgwPvlaZHK3SpvKHa6orETPOtn9S7vZ0OuxzmtMn/iPW6zuuQhIS6N QjXA/qp9oj+w== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="434085297" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:43:49 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:19 +0200 Message-Id: <44491f2465549ea5c2e48cde5437fa232f77ab96.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 02/10] drm/i915: migrate hsw fdi code to new file. 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie Daniel asked for this, but it's a bit messy and I'm not sure how best to clean it up yet. Signed-off-by: Dave Airlie [Jani: also moved fdi buf trans to intel_fdi.c.] Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_crt.c | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 151 ++--------------------- drivers/gpu/drm/i915/display/intel_ddi.h | 8 +- drivers/gpu/drm/i915/display/intel_fdi.c | 139 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_fdi.h | 3 + 5 files changed, 156 insertions(+), 146 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 4934edd51cb0..077ebc7e6396 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -38,6 +38,7 @@ #include "intel_crt.h" #include "intel_ddi.h" #include "intel_display_types.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hotplug.h" diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e2b82e0557e7..28877a31adc0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -36,10 +36,11 @@ #include "intel_ddi_buf_trans.h" #include "intel_display_types.h" #include "intel_dp.h" -#include "intel_dp_mst.h" #include "intel_dp_link_training.h" +#include "intel_dp_mst.h" #include "intel_dpio_phy.h" #include "intel_dsi.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hdcp.h" @@ -91,8 +92,8 @@ static int intel_ddi_hdmi_level(struct intel_encoder *encoder, * values in advance. This function programs the correct values for * DP/eDP/FDI use cases. */ -static void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 iboost_bit = 0; @@ -154,8 +155,8 @@ static void intel_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, ddi_translations[level].trans2); } -static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, - enum port port) +void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port) { if (IS_BROXTON(dev_priv)) { udelay(16); @@ -183,7 +184,7 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv, port_name(port)); } -static u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) +u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) { switch (pll->info->id) { case DPLL_ID_WRPLL1: @@ -243,144 +244,6 @@ static u32 icl_pll_to_ddi_clk_sel(struct intel_encoder *encoder, } } -/* Starting with Haswell, different DDI ports can work in FDI mode for - * connection to the PCH-located connectors. For this, it is necessary to train - * both the DDI port and PCH receiver for the desired DDI buffer settings. - * - * The recommended port to work in FDI mode is DDI E, which we use here. Also, - * please note that when FDI mode is active on DDI E, it shares 2 lines with - * DDI A (which is used for eDP) - */ - -void hsw_fdi_link_train(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - u32 temp, i, rx_ctl_val, ddi_pll_sel; - int n_entries; - - intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); - - intel_prepare_dp_ddi_buffers(encoder, crtc_state); - - /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the - * mode set "sequence for CRT port" document: - * - TP1 to TP2 time with the default value - * - FDI delay to 90h - * - * WaFDIAutoLinkSetTimingOverrride:hsw - */ - intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), - FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); - - /* Enable the PCH Receiver FDI PLL */ - rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | - FDI_RX_PLL_ENABLE | - FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes); - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); - udelay(220); - - /* Switch from Rawclk to PCDclk */ - rx_ctl_val |= FDI_PCDCLK; - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - - /* Configure Port Clock Select */ - ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll); - intel_de_write(dev_priv, PORT_CLK_SEL(PORT_E), ddi_pll_sel); - drm_WARN_ON(&dev_priv->drm, ddi_pll_sel != PORT_CLK_SEL_SPLL); - - /* Start the training iterating through available voltages and emphasis, - * testing each value twice. */ - for (i = 0; i < n_entries * 2; i++) { - /* Configure DP_TP_CTL with auto-training */ - intel_de_write(dev_priv, DP_TP_CTL(PORT_E), - DP_TP_CTL_FDI_AUTOTRAIN | - DP_TP_CTL_ENHANCED_FRAME_ENABLE | - DP_TP_CTL_LINK_TRAIN_PAT1 | - DP_TP_CTL_ENABLE); - - /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. - * DDI E does not support port reversal, the functionality is - * achieved on the PCH side in FDI_RX_CTL, so no need to set the - * port reversal bit */ - intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), - DDI_BUF_CTL_ENABLE | ((crtc_state->fdi_lanes - 1) << 1) | DDI_BUF_TRANS_SELECT(i / 2)); - intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); - - udelay(600); - - /* Program PCH FDI Receiver TU */ - intel_de_write(dev_priv, FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64)); - - /* Enable PCH FDI Receiver with auto-training */ - rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); - - /* Wait for FDI receiver lane calibration */ - udelay(30); - - /* Unset FDI_RX_MISC pwrdn lanes */ - temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); - temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); - intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); - intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); - - /* Wait for FDI auto training time */ - udelay(5); - - temp = intel_de_read(dev_priv, DP_TP_STATUS(PORT_E)); - if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { - drm_dbg_kms(&dev_priv->drm, - "FDI link training done on step %d\n", i); - break; - } - - /* - * Leave things enabled even if we failed to train FDI. - * Results in less fireworks from the state checker. - */ - if (i == n_entries * 2 - 1) { - drm_err(&dev_priv->drm, "FDI link training failed!\n"); - break; - } - - rx_ctl_val &= ~FDI_RX_ENABLE; - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); - - temp = intel_de_read(dev_priv, DDI_BUF_CTL(PORT_E)); - temp &= ~DDI_BUF_CTL_ENABLE; - intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), temp); - intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); - - /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ - temp = intel_de_read(dev_priv, DP_TP_CTL(PORT_E)); - temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); - temp |= DP_TP_CTL_LINK_TRAIN_PAT1; - intel_de_write(dev_priv, DP_TP_CTL(PORT_E), temp); - intel_de_posting_read(dev_priv, DP_TP_CTL(PORT_E)); - - intel_wait_ddi_buf_idle(dev_priv, PORT_E); - - /* Reset FDI_RX_MISC pwrdn lanes */ - temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); - temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); - temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); - intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); - intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); - } - - /* Enable normal pixel sending for FDI */ - intel_de_write(dev_priv, DP_TP_CTL(PORT_E), - DP_TP_CTL_FDI_AUTOTRAIN | - DP_TP_CTL_LINK_TRAIN_NORMAL | - DP_TP_CTL_ENHANCED_FRAME_ENABLE | - DP_TP_CTL_ENABLE); -} - static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index a4dd815c0000..f9a916cad7e7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -17,6 +17,7 @@ struct intel_crtc_state; struct intel_dp; struct intel_dpll_hw_state; struct intel_encoder; +struct intel_shared_dpll; enum transcoder; i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder, @@ -27,8 +28,11 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, struct intel_encoder *intel_encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state); -void hsw_fdi_link_train(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); +u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll); +void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); +void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port); void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port); bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe); void intel_ddi_enable_transcoder_func(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index b2eb96ae10a2..77df675e607e 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -3,6 +3,8 @@ * Copyright © 2020 Intel Corporation */ #include "intel_atomic.h" +#include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" #include "intel_display_types.h" #include "intel_fdi.h" @@ -550,6 +552,143 @@ static void ivb_manual_fdi_link_train(struct intel_crtc *crtc, drm_dbg_kms(&dev_priv->drm, "FDI train done.\n"); } +/* Starting with Haswell, different DDI ports can work in FDI mode for + * connection to the PCH-located connectors. For this, it is necessary to train + * both the DDI port and PCH receiver for the desired DDI buffer settings. + * + * The recommended port to work in FDI mode is DDI E, which we use here. Also, + * please note that when FDI mode is active on DDI E, it shares 2 lines with + * DDI A (which is used for eDP) + */ +void hsw_fdi_link_train(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + u32 temp, i, rx_ctl_val, ddi_pll_sel; + int n_entries; + + intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); + + intel_prepare_dp_ddi_buffers(encoder, crtc_state); + + /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the + * mode set "sequence for CRT port" document: + * - TP1 to TP2 time with the default value + * - FDI delay to 90h + * + * WaFDIAutoLinkSetTimingOverrride:hsw + */ + intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), + FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + + /* Enable the PCH Receiver FDI PLL */ + rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | + FDI_RX_PLL_ENABLE | + FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes); + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); + udelay(220); + + /* Switch from Rawclk to PCDclk */ + rx_ctl_val |= FDI_PCDCLK; + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + + /* Configure Port Clock Select */ + ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll); + intel_de_write(dev_priv, PORT_CLK_SEL(PORT_E), ddi_pll_sel); + drm_WARN_ON(&dev_priv->drm, ddi_pll_sel != PORT_CLK_SEL_SPLL); + + /* Start the training iterating through available voltages and emphasis, + * testing each value twice. */ + for (i = 0; i < n_entries * 2; i++) { + /* Configure DP_TP_CTL with auto-training */ + intel_de_write(dev_priv, DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_LINK_TRAIN_PAT1 | + DP_TP_CTL_ENABLE); + + /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. + * DDI E does not support port reversal, the functionality is + * achieved on the PCH side in FDI_RX_CTL, so no need to set the + * port reversal bit */ + intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), + DDI_BUF_CTL_ENABLE | ((crtc_state->fdi_lanes - 1) << 1) | DDI_BUF_TRANS_SELECT(i / 2)); + intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); + + udelay(600); + + /* Program PCH FDI Receiver TU */ + intel_de_write(dev_priv, FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64)); + + /* Enable PCH FDI Receiver with auto-training */ + rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); + + /* Wait for FDI receiver lane calibration */ + udelay(30); + + /* Unset FDI_RX_MISC pwrdn lanes */ + temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); + intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); + + /* Wait for FDI auto training time */ + udelay(5); + + temp = intel_de_read(dev_priv, DP_TP_STATUS(PORT_E)); + if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { + drm_dbg_kms(&dev_priv->drm, + "FDI link training done on step %d\n", i); + break; + } + + /* + * Leave things enabled even if we failed to train FDI. + * Results in less fireworks from the state checker. + */ + if (i == n_entries * 2 - 1) { + drm_err(&dev_priv->drm, "FDI link training failed!\n"); + break; + } + + rx_ctl_val &= ~FDI_RX_ENABLE; + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); + + temp = intel_de_read(dev_priv, DDI_BUF_CTL(PORT_E)); + temp &= ~DDI_BUF_CTL_ENABLE; + intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), temp); + intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); + + /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ + temp = intel_de_read(dev_priv, DP_TP_CTL(PORT_E)); + temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + temp |= DP_TP_CTL_LINK_TRAIN_PAT1; + intel_de_write(dev_priv, DP_TP_CTL(PORT_E), temp); + intel_de_posting_read(dev_priv, DP_TP_CTL(PORT_E)); + + intel_wait_ddi_buf_idle(dev_priv, PORT_E); + + /* Reset FDI_RX_MISC pwrdn lanes */ + temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); + intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); + intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); + } + + /* Enable normal pixel sending for FDI */ + intel_de_write(dev_priv, DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_LINK_TRAIN_NORMAL | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_ENABLE); +} + void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index a9cd21663eb8..af01d2c173a8 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -9,6 +9,7 @@ struct drm_i915_private; struct intel_crtc; struct intel_crtc_state; +struct intel_encoder; #define I915_DISPLAY_CONFIG_RETRY 1 int ilk_fdi_compute_config(struct intel_crtc *intel_crtc, @@ -18,5 +19,7 @@ void ilk_fdi_disable(struct intel_crtc *crtc); void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc); void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state); void intel_fdi_init_hook(struct drm_i915_private *dev_priv); +void hsw_fdi_link_train(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); #endif From patchwork Thu Feb 4 19:43:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068541 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8465C433DB for ; Thu, 4 Feb 2021 19:44:04 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 63D6464F6D for ; Thu, 4 Feb 2021 19:44:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 63D6464F6D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E1EB26EE4B; Thu, 4 Feb 2021 19:44:03 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id D2E9B6EE4B for ; Thu, 4 Feb 2021 19:44:01 +0000 (UTC) IronPort-SDR: faXRLEAsLWNQ8w2JAKKSQDS1tO9dacHc+cGXl9iwVpAFwGz7E8+BgWxPFjPmoNc7Puvj/I+z7j nXkBpxvymjyw== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="245387729" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="245387729" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:00 -0800 IronPort-SDR: iW7JTFxND+7cI1VqsFqt6L9y2l3+WURiFathRN5SSDcvJUhQsZrVeXsxG14PJ3TUIA67E338Yq 2DNGZ5KF1rWw== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="483684547" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:43:55 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:20 +0200 Message-Id: X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 03/10] drm/i915: migrate skl planes code new file (v5) 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, Dave Airlie , Dan Carpenter Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie Rework the plane init calls to do the gen test one level higher. Rework some of the plane helpers so they can live in new file, there is still some scope to clean up the plane/fb interactions later. v2: drop atomic code back, rename file to Ville suggestions, add header file. v3: move scaler bits back v4: drop wrong new includes (Ville) v5: integrate the ccs gen12 changes Signed-off-by: Dave Airlie [Jani: fixed up sparse warnings.] Signed-off-by: Jani Nikula Reported-by: kernel test robot Reported-by: Dan Carpenter --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/i9xx_plane.c | 4 - drivers/gpu/drm/i915/display/icl_dsi.c | 1 + drivers/gpu/drm/i915/display/intel_crtc.c | 13 +- drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 970 +------ drivers/gpu/drm/i915/display/intel_display.h | 27 +- .../drm/i915/display/intel_display_types.h | 27 + drivers/gpu/drm/i915/display/intel_psr.c | 1 + drivers/gpu/drm/i915/display/intel_sprite.c | 1343 +--------- drivers/gpu/drm/i915/display/intel_sprite.h | 6 +- .../drm/i915/display/skl_universal_plane.c | 2265 +++++++++++++++++ .../drm/i915/display/skl_universal_plane.h | 33 + drivers/gpu/drm/i915/intel_pm.c | 1 + 14 files changed, 2391 insertions(+), 2304 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/skl_universal_plane.c create mode 100644 drivers/gpu/drm/i915/display/skl_universal_plane.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d571e87416dc..9388e09184fe 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -225,7 +225,8 @@ i915-y += \ display/intel_sprite.o \ display/intel_tc.o \ display/intel_vga.o \ - display/i9xx_plane.o + display/i9xx_plane.o \ + display/skl_universal_plane.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index d30374df67f0..d116dee201aa 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -743,10 +743,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) int num_formats; int ret, zpos; - if (INTEL_GEN(dev_priv) >= 9) - return skl_universal_plane_create(dev_priv, pipe, - PLANE_PRIMARY); - plane = intel_plane_alloc(); if (IS_ERR(plane)) return plane; diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 9d245a689323..9eeec6fadec7 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -35,6 +35,7 @@ #include "intel_dsi.h" #include "intel_panel.h" #include "intel_vdsc.h" +#include "skl_universal_plane.h" static int header_credits_available(struct drm_i915_private *dev_priv, enum transcoder dsi_trans) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 57b0a3ebe908..eb478712c381 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -20,6 +20,7 @@ #include "intel_pipe_crc.h" #include "intel_sprite.h" #include "i9xx_plane.h" +#include "skl_universal_plane.h" static void assert_vblank_disabled(struct drm_crtc *crtc) { @@ -243,7 +244,11 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) crtc->pipe = pipe; crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe]; - primary = intel_primary_plane_create(dev_priv, pipe); + if (INTEL_GEN(dev_priv) >= 9) + primary = skl_universal_plane_create(dev_priv, pipe, + PLANE_PRIMARY); + else + primary = intel_primary_plane_create(dev_priv, pipe); if (IS_ERR(primary)) { ret = PTR_ERR(primary); goto fail; @@ -253,7 +258,11 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) for_each_sprite(dev_priv, pipe, sprite) { struct intel_plane *plane; - plane = intel_sprite_plane_create(dev_priv, pipe, sprite); + if (INTEL_GEN(dev_priv) >= 9) + plane = skl_universal_plane_create(dev_priv, pipe, + PLANE_SPRITE0 + sprite); + else + plane = intel_sprite_plane_create(dev_priv, pipe, sprite); if (IS_ERR(plane)) { ret = PTR_ERR(plane); goto fail; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 28877a31adc0..f4746c1edabe 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -54,6 +54,7 @@ #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vrr.h" +#include "skl_universal_plane.h" static const u8 index_to_dp_signal_levels[] = { [0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index aca964f7ba72..8211cb40b5c6 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -94,6 +94,7 @@ #include "intel_tc.h" #include "intel_vga.h" #include "i9xx_plane.h" +#include "skl_universal_plane.h" static void i9xx_crtc_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); @@ -116,7 +117,6 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); static void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); -static void skl_pfit_enable(const struct intel_crtc_state *crtc_state); static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); @@ -1082,32 +1082,6 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv) return IS_GEN(dev_priv, 2) ? 2048 : 4096; } -static bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) -{ - if (!is_ccs_modifier(fb->modifier)) - return false; - - return plane >= fb->format->num_planes / 2; -} - -static bool is_gen12_ccs_modifier(u64 modifier) -{ - return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; -} - -static bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane) -{ - return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane); -} - -static bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) -{ - return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC && - plane == 2; -} - static bool is_aux_plane(const struct drm_framebuffer *fb, int plane) { if (is_ccs_modifier(fb->modifier)) @@ -1116,38 +1090,6 @@ static bool is_aux_plane(const struct drm_framebuffer *fb, int plane) return plane == 1; } -static int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) -{ - drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || - (main_plane && main_plane >= fb->format->num_planes / 2)); - - return fb->format->num_planes / 2 + main_plane; -} - -static int ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) -{ - drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || - ccs_plane < fb->format->num_planes / 2); - - if (is_gen12_ccs_cc_plane(fb, ccs_plane)) - return 0; - - return ccs_plane - fb->format->num_planes / 2; -} - -int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) -{ - struct drm_i915_private *i915 = to_i915(fb->dev); - - if (is_ccs_modifier(fb->modifier)) - return main_to_ccs_plane(fb, main_plane); - else if (INTEL_GEN(i915) < 11 && - intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - return 1; - else - return 0; -} - bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, u64 modifier) @@ -1163,7 +1105,7 @@ static bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, color_plane == 1; } -static unsigned int +unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); @@ -1217,7 +1159,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) } } -static unsigned int +unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) { if (is_gen12_ccs_plane(fb, color_plane)) @@ -1322,8 +1264,8 @@ static bool has_async_flips(struct drm_i915_private *i915) return INTEL_GEN(i915) >= 5; } -static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, - int color_plane) +unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, + int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); @@ -1590,10 +1532,10 @@ static u32 intel_adjust_aligned_offset(int *x, int *y, * Adjust the tile offset by moving the difference into * the x/y offsets. */ -static u32 intel_plane_adjust_aligned_offset(int *x, int *y, - const struct intel_plane_state *state, - int color_plane, - u32 old_offset, u32 new_offset) +u32 intel_plane_adjust_aligned_offset(int *x, int *y, + const struct intel_plane_state *state, + int color_plane, + u32 old_offset, u32 new_offset) { return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane, state->hw.rotation, @@ -1892,7 +1834,7 @@ bool is_ccs_modifier(u64 modifier) static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane) { - return DIV_ROUND_UP(fb->pitches[ccs_to_main_plane(fb, ccs_plane)], + return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)], 512) * 64; } @@ -2050,7 +1992,7 @@ static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state) return stride > max_stride; } -static void +void intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int color_plane) @@ -2075,7 +2017,7 @@ intel_fb_plane_get_subsampling(int *hsub, int *vsub, return; } - main_plane = ccs_to_main_plane(fb, color_plane); + main_plane = skl_ccs_to_main_plane(fb, color_plane); *hsub = drm_format_info_block_width(fb->format, color_plane) / drm_format_info_block_width(fb->format, main_plane); @@ -2115,7 +2057,7 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int ccs_plane, int x, int y) ccs_x = (x * hsub) % tile_width; ccs_y = (y * vsub) % tile_height; - main_plane = ccs_to_main_plane(fb, ccs_plane); + main_plane = skl_ccs_to_main_plane(fb, ccs_plane); main_x = intel_fb->normal[main_plane].x % tile_width; main_y = intel_fb->normal[main_plane].y % tile_height; @@ -2141,7 +2083,7 @@ static void intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane) { int main_plane = is_ccs_plane(fb, color_plane) ? - ccs_to_main_plane(fb, color_plane) : 0; + skl_ccs_to_main_plane(fb, color_plane) : 0; int main_hsub, main_vsub; int hsub, vsub; @@ -2528,73 +2470,6 @@ static int i9xx_format_to_fourcc(int format) } } -int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) -{ - switch (format) { - case PLANE_CTL_FORMAT_RGB_565: - return DRM_FORMAT_RGB565; - case PLANE_CTL_FORMAT_NV12: - return DRM_FORMAT_NV12; - case PLANE_CTL_FORMAT_XYUV: - return DRM_FORMAT_XYUV8888; - case PLANE_CTL_FORMAT_P010: - return DRM_FORMAT_P010; - case PLANE_CTL_FORMAT_P012: - return DRM_FORMAT_P012; - case PLANE_CTL_FORMAT_P016: - return DRM_FORMAT_P016; - case PLANE_CTL_FORMAT_Y210: - return DRM_FORMAT_Y210; - case PLANE_CTL_FORMAT_Y212: - return DRM_FORMAT_Y212; - case PLANE_CTL_FORMAT_Y216: - return DRM_FORMAT_Y216; - case PLANE_CTL_FORMAT_Y410: - return DRM_FORMAT_XVYU2101010; - case PLANE_CTL_FORMAT_Y412: - return DRM_FORMAT_XVYU12_16161616; - case PLANE_CTL_FORMAT_Y416: - return DRM_FORMAT_XVYU16161616; - default: - case PLANE_CTL_FORMAT_XRGB_8888: - if (rgb_order) { - if (alpha) - return DRM_FORMAT_ABGR8888; - else - return DRM_FORMAT_XBGR8888; - } else { - if (alpha) - return DRM_FORMAT_ARGB8888; - else - return DRM_FORMAT_XRGB8888; - } - case PLANE_CTL_FORMAT_XRGB_2101010: - if (rgb_order) { - if (alpha) - return DRM_FORMAT_ABGR2101010; - else - return DRM_FORMAT_XBGR2101010; - } else { - if (alpha) - return DRM_FORMAT_ARGB2101010; - else - return DRM_FORMAT_XRGB2101010; - } - case PLANE_CTL_FORMAT_XRGB_16161616F: - if (rgb_order) { - if (alpha) - return DRM_FORMAT_ABGR16161616F; - else - return DRM_FORMAT_XBGR16161616F; - } else { - if (alpha) - return DRM_FORMAT_ARGB16161616F; - else - return DRM_FORMAT_XRGB16161616F; - } - } -} - static struct i915_vma * initial_plane_vma(struct drm_i915_private *i915, struct intel_initial_plane_config *plane_config) @@ -2899,367 +2774,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, &to_intel_frontbuffer(fb)->bits); } - -static bool -skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state, - int main_x, int main_y, u32 main_offset, - int ccs_plane) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - int aux_x = plane_state->color_plane[ccs_plane].x; - int aux_y = plane_state->color_plane[ccs_plane].y; - u32 aux_offset = plane_state->color_plane[ccs_plane].offset; - u32 alignment = intel_surf_alignment(fb, ccs_plane); - int hsub; - int vsub; - - intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); - while (aux_offset >= main_offset && aux_y <= main_y) { - int x, y; - - if (aux_x == main_x && aux_y == main_y) - break; - - if (aux_offset == 0) - break; - - x = aux_x / hsub; - y = aux_y / vsub; - aux_offset = intel_plane_adjust_aligned_offset(&x, &y, - plane_state, - ccs_plane, - aux_offset, - aux_offset - - alignment); - aux_x = x * hsub + aux_x % hsub; - aux_y = y * vsub + aux_y % vsub; - } - - if (aux_x != main_x || aux_y != main_y) - return false; - - plane_state->color_plane[ccs_plane].offset = aux_offset; - plane_state->color_plane[ccs_plane].x = aux_x; - plane_state->color_plane[ccs_plane].y = aux_y; - - return true; -} - -unsigned int -intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) -{ - int x = 0, y = 0; - - intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, - plane_state->color_plane[0].offset, 0); - - return y; -} - -static int intel_plane_min_width(struct intel_plane *plane, - const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - if (plane->min_width) - return plane->min_width(fb, color_plane, rotation); - else - return 1; -} - -static int intel_plane_max_width(struct intel_plane *plane, - const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - if (plane->max_width) - return plane->max_width(fb, color_plane, rotation); - else - return INT_MAX; -} - -static int intel_plane_max_height(struct intel_plane *plane, - const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - if (plane->max_height) - return plane->max_height(fb, color_plane, rotation); - else - return INT_MAX; -} - -int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, - int *x, int *y, u32 *offset) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - const int aux_plane = intel_main_to_aux_plane(fb, 0); - const u32 aux_offset = plane_state->color_plane[aux_plane].offset; - const u32 alignment = intel_surf_alignment(fb, 0); - const int w = drm_rect_width(&plane_state->uapi.src) >> 16; - - intel_add_fb_offsets(x, y, plane_state, 0); - *offset = intel_plane_compute_aligned_offset(x, y, plane_state, 0); - if (drm_WARN_ON(&dev_priv->drm, alignment && !is_power_of_2(alignment))) - return -EINVAL; - - /* - * AUX surface offset is specified as the distance from the - * main surface offset, and it must be non-negative. Make - * sure that is what we will get. - */ - if (aux_plane && *offset > aux_offset) - *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, - *offset, - aux_offset & ~(alignment - 1)); - - /* - * When using an X-tiled surface, the plane blows up - * if the x offset + width exceed the stride. - * - * TODO: linear and Y-tiled seem fine, Yf untested, - */ - if (fb->modifier == I915_FORMAT_MOD_X_TILED) { - int cpp = fb->format->cpp[0]; - - while ((*x + w) * cpp > plane_state->color_plane[0].stride) { - if (*offset == 0) { - drm_dbg_kms(&dev_priv->drm, - "Unable to find suitable display surface offset due to X-tiling\n"); - return -EINVAL; - } - - *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, - *offset, - *offset - alignment); - } - } - - return 0; -} - -static int skl_check_main_surface(struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - const unsigned int rotation = plane_state->hw.rotation; - int x = plane_state->uapi.src.x1 >> 16; - int y = plane_state->uapi.src.y1 >> 16; - const int w = drm_rect_width(&plane_state->uapi.src) >> 16; - const int h = drm_rect_height(&plane_state->uapi.src) >> 16; - const int min_width = intel_plane_min_width(plane, fb, 0, rotation); - const int max_width = intel_plane_max_width(plane, fb, 0, rotation); - const int max_height = intel_plane_max_height(plane, fb, 0, rotation); - const int aux_plane = intel_main_to_aux_plane(fb, 0); - const u32 alignment = intel_surf_alignment(fb, 0); - u32 offset; - int ret; - - if (w > max_width || w < min_width || h > max_height) { - drm_dbg_kms(&dev_priv->drm, - "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n", - w, h, min_width, max_width, max_height); - return -EINVAL; - } - - ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset); - if (ret) - return ret; - - /* - * CCS AUX surface doesn't have its own x/y offsets, we must make sure - * they match with the main surface x/y offsets. - */ - if (is_ccs_modifier(fb->modifier)) { - while (!skl_check_main_ccs_coordinates(plane_state, x, y, - offset, aux_plane)) { - if (offset == 0) - break; - - offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, - offset, offset - alignment); - } - - if (x != plane_state->color_plane[aux_plane].x || - y != plane_state->color_plane[aux_plane].y) { - drm_dbg_kms(&dev_priv->drm, - "Unable to find suitable display surface offset due to CCS\n"); - return -EINVAL; - } - } - - drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191); - - plane_state->color_plane[0].offset = offset; - plane_state->color_plane[0].x = x; - plane_state->color_plane[0].y = y; - - /* - * Put the final coordinates back so that the src - * coordinate checks will see the right values. - */ - drm_rect_translate_to(&plane_state->uapi.src, - x << 16, y << 16); - - return 0; -} - -static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *i915 = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - int uv_plane = 1; - int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation); - int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation); - int x = plane_state->uapi.src.x1 >> 17; - int y = plane_state->uapi.src.y1 >> 17; - int w = drm_rect_width(&plane_state->uapi.src) >> 17; - int h = drm_rect_height(&plane_state->uapi.src) >> 17; - u32 offset; - - /* FIXME not quite sure how/if these apply to the chroma plane */ - if (w > max_width || h > max_height) { - drm_dbg_kms(&i915->drm, - "CbCr source size %dx%d too big (limit %dx%d)\n", - w, h, max_width, max_height); - return -EINVAL; - } - - intel_add_fb_offsets(&x, &y, plane_state, uv_plane); - offset = intel_plane_compute_aligned_offset(&x, &y, - plane_state, uv_plane); - - if (is_ccs_modifier(fb->modifier)) { - int ccs_plane = main_to_ccs_plane(fb, uv_plane); - u32 aux_offset = plane_state->color_plane[ccs_plane].offset; - u32 alignment = intel_surf_alignment(fb, uv_plane); - - if (offset > aux_offset) - offset = intel_plane_adjust_aligned_offset(&x, &y, - plane_state, - uv_plane, - offset, - aux_offset & ~(alignment - 1)); - - while (!skl_check_main_ccs_coordinates(plane_state, x, y, - offset, ccs_plane)) { - if (offset == 0) - break; - - offset = intel_plane_adjust_aligned_offset(&x, &y, - plane_state, - uv_plane, - offset, offset - alignment); - } - - if (x != plane_state->color_plane[ccs_plane].x || - y != plane_state->color_plane[ccs_plane].y) { - drm_dbg_kms(&i915->drm, - "Unable to find suitable display surface offset due to CCS\n"); - return -EINVAL; - } - } - - drm_WARN_ON(&i915->drm, x > 8191 || y > 8191); - - plane_state->color_plane[uv_plane].offset = offset; - plane_state->color_plane[uv_plane].x = x; - plane_state->color_plane[uv_plane].y = y; - - return 0; -} - -static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - int src_x = plane_state->uapi.src.x1 >> 16; - int src_y = plane_state->uapi.src.y1 >> 16; - u32 offset; - int ccs_plane; - - for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) { - int main_hsub, main_vsub; - int hsub, vsub; - int x, y; - - if (!is_ccs_plane(fb, ccs_plane) || - is_gen12_ccs_cc_plane(fb, ccs_plane)) - continue; - - intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, - ccs_to_main_plane(fb, ccs_plane)); - intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); - - hsub *= main_hsub; - vsub *= main_vsub; - x = src_x / hsub; - y = src_y / vsub; - - intel_add_fb_offsets(&x, &y, plane_state, ccs_plane); - - offset = intel_plane_compute_aligned_offset(&x, &y, - plane_state, - ccs_plane); - - plane_state->color_plane[ccs_plane].offset = offset; - plane_state->color_plane[ccs_plane].x = (x * hsub + - src_x % hsub) / - main_hsub; - plane_state->color_plane[ccs_plane].y = (y * vsub + - src_y % vsub) / - main_vsub; - } - - return 0; -} - -int skl_check_plane_surface(struct intel_plane_state *plane_state) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - int ret, i; - - ret = intel_plane_compute_gtt(plane_state); - if (ret) - return ret; - - if (!plane_state->uapi.visible) - return 0; - - /* - * Handle the AUX surface first since the main surface setup depends on - * it. - */ - if (is_ccs_modifier(fb->modifier)) { - ret = skl_check_ccs_aux_surface(plane_state); - if (ret) - return ret; - } - - if (intel_format_info_is_yuv_semiplanar(fb->format, - fb->modifier)) { - ret = skl_check_nv12_aux_surface(plane_state); - if (ret) - return ret; - } - - for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) { - plane_state->color_plane[i].offset = 0; - plane_state->color_plane[i].x = 0; - plane_state->color_plane[i].y = 0; - } - - ret = skl_check_main_surface(plane_state); - if (ret) - return ret; - - return 0; -} - static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) { struct drm_device *dev = intel_crtc->base.dev; @@ -3292,305 +2806,24 @@ static void skl_detach_scalers(const struct intel_crtc_state *crtc_state) } } -static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb, - int color_plane, unsigned int rotation) -{ - /* - * The stride is either expressed as a multiple of 64 bytes chunks for - * linear buffers or in number of tiles for tiled buffers. - */ - if (is_surface_linear(fb, color_plane)) - return 64; - else if (drm_rotation_90_or_270(rotation)) - return intel_tile_height(fb, color_plane); - else - return intel_tile_width_bytes(fb, color_plane); -} - -u32 skl_plane_stride(const struct intel_plane_state *plane_state, - int color_plane) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - u32 stride = plane_state->color_plane[color_plane].stride; - - if (color_plane >= fb->format->num_planes) - return 0; - - return stride / skl_plane_stride_mult(fb, color_plane, rotation); -} - -static u32 skl_plane_ctl_format(u32 pixel_format) -{ - switch (pixel_format) { - case DRM_FORMAT_C8: - return PLANE_CTL_FORMAT_INDEXED; - case DRM_FORMAT_RGB565: - return PLANE_CTL_FORMAT_RGB_565; - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: - return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - return PLANE_CTL_FORMAT_XRGB_8888; - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ABGR2101010: - return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX; - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_ARGB2101010: - return PLANE_CTL_FORMAT_XRGB_2101010; - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX; - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - return PLANE_CTL_FORMAT_XRGB_16161616F; - case DRM_FORMAT_XYUV8888: - return PLANE_CTL_FORMAT_XYUV; - case DRM_FORMAT_YUYV: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; - case DRM_FORMAT_YVYU: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; - case DRM_FORMAT_UYVY: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; - case DRM_FORMAT_VYUY: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; - case DRM_FORMAT_NV12: - return PLANE_CTL_FORMAT_NV12; - case DRM_FORMAT_P010: - return PLANE_CTL_FORMAT_P010; - case DRM_FORMAT_P012: - return PLANE_CTL_FORMAT_P012; - case DRM_FORMAT_P016: - return PLANE_CTL_FORMAT_P016; - case DRM_FORMAT_Y210: - return PLANE_CTL_FORMAT_Y210; - case DRM_FORMAT_Y212: - return PLANE_CTL_FORMAT_Y212; - case DRM_FORMAT_Y216: - return PLANE_CTL_FORMAT_Y216; - case DRM_FORMAT_XVYU2101010: - return PLANE_CTL_FORMAT_Y410; - case DRM_FORMAT_XVYU12_16161616: - return PLANE_CTL_FORMAT_Y412; - case DRM_FORMAT_XVYU16161616: - return PLANE_CTL_FORMAT_Y416; - default: - MISSING_CASE(pixel_format); - } - - return 0; -} - -static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state) -{ - if (!plane_state->hw.fb->format->has_alpha) - return PLANE_CTL_ALPHA_DISABLE; - - switch (plane_state->hw.pixel_blend_mode) { - case DRM_MODE_BLEND_PIXEL_NONE: - return PLANE_CTL_ALPHA_DISABLE; - case DRM_MODE_BLEND_PREMULTI: - return PLANE_CTL_ALPHA_SW_PREMULTIPLY; - case DRM_MODE_BLEND_COVERAGE: - return PLANE_CTL_ALPHA_HW_PREMULTIPLY; - default: - MISSING_CASE(plane_state->hw.pixel_blend_mode); - return PLANE_CTL_ALPHA_DISABLE; - } -} - -static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state) -{ - if (!plane_state->hw.fb->format->has_alpha) - return PLANE_COLOR_ALPHA_DISABLE; - - switch (plane_state->hw.pixel_blend_mode) { - case DRM_MODE_BLEND_PIXEL_NONE: - return PLANE_COLOR_ALPHA_DISABLE; - case DRM_MODE_BLEND_PREMULTI: - return PLANE_COLOR_ALPHA_SW_PREMULTIPLY; - case DRM_MODE_BLEND_COVERAGE: - return PLANE_COLOR_ALPHA_HW_PREMULTIPLY; - default: - MISSING_CASE(plane_state->hw.pixel_blend_mode); - return PLANE_COLOR_ALPHA_DISABLE; - } -} - -static u32 skl_plane_ctl_tiling(u64 fb_modifier) -{ - switch (fb_modifier) { - case DRM_FORMAT_MOD_LINEAR: - break; - case I915_FORMAT_MOD_X_TILED: - return PLANE_CTL_TILED_X; - case I915_FORMAT_MOD_Y_TILED: - return PLANE_CTL_TILED_Y; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: - return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: - return PLANE_CTL_TILED_Y | - PLANE_CTL_RENDER_DECOMPRESSION_ENABLE | - PLANE_CTL_CLEAR_COLOR_DISABLE; - case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE; - case I915_FORMAT_MOD_Yf_TILED: - return PLANE_CTL_TILED_YF; - case I915_FORMAT_MOD_Yf_TILED_CCS: - return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; - default: - MISSING_CASE(fb_modifier); - } - - return 0; -} - -static u32 skl_plane_ctl_rotate(unsigned int rotate) -{ - switch (rotate) { - case DRM_MODE_ROTATE_0: - break; - /* - * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr - * while i915 HW rotation is clockwise, thats why this swapping. - */ - case DRM_MODE_ROTATE_90: - return PLANE_CTL_ROTATE_270; - case DRM_MODE_ROTATE_180: - return PLANE_CTL_ROTATE_180; - case DRM_MODE_ROTATE_270: - return PLANE_CTL_ROTATE_90; - default: - MISSING_CASE(rotate); - } - - return 0; -} - -static u32 cnl_plane_ctl_flip(unsigned int reflect) -{ - switch (reflect) { - case 0: - break; - case DRM_MODE_REFLECT_X: - return PLANE_CTL_FLIP_HORIZONTAL; - case DRM_MODE_REFLECT_Y: - default: - MISSING_CASE(reflect); - } - - return 0; -} - -u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - u32 plane_ctl = 0; - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - return plane_ctl; - - if (crtc_state->gamma_enable) - plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE; - - if (crtc_state->csc_enable) - plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE; - - return plane_ctl; -} - -u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 plane_ctl; - - plane_ctl = PLANE_CTL_ENABLE; - - if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { - plane_ctl |= skl_plane_ctl_alpha(plane_state); - plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; - - if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709) - plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709; - - if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) - plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE; - } - - plane_ctl |= skl_plane_ctl_format(fb->format->format); - plane_ctl |= skl_plane_ctl_tiling(fb->modifier); - plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK); - - if (INTEL_GEN(dev_priv) >= 10) - plane_ctl |= cnl_plane_ctl_flip(rotation & - DRM_MODE_REFLECT_MASK); - - if (key->flags & I915_SET_COLORKEY_DESTINATION) - plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; - else if (key->flags & I915_SET_COLORKEY_SOURCE) - plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; - - return plane_ctl; -} - -u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state) +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - u32 plane_color_ctl = 0; - - if (INTEL_GEN(dev_priv) >= 11) - return plane_color_ctl; - - if (crtc_state->gamma_enable) - plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE; - - if (crtc_state->csc_enable) - plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE; + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); + int i; - return plane_color_ctl; + for (i = 0; i < crtc->num_scalers; i++) + skl_detach_scaler(crtc, i); } -u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +unsigned int +intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - u32 plane_color_ctl = 0; - - plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; - plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state); + int x = 0, y = 0; - if (fb->format->is_yuv && !icl_is_hdr_plane(dev_priv, plane->id)) { - switch (plane_state->hw.color_encoding) { - case DRM_COLOR_YCBCR_BT709: - plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; - break; - case DRM_COLOR_YCBCR_BT2020: - plane_color_ctl |= - PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020; - break; - default: - plane_color_ctl |= - PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601; - } - if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) - plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; - } else if (fb->format->is_yuv) { - plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE; - if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) - plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; - } + intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, + plane_state->color_plane[0].offset, 0); - return plane_color_ctl; + return y; } static int @@ -4445,15 +3678,6 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, return 0; } -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); - int i; - - for (i = 0; i < crtc->num_scalers; i++) - skl_detach_scaler(crtc, i); -} - static int cnl_coef_tap(int i) { return i % 7; @@ -8276,150 +7500,6 @@ static void skl_get_pfit_config(struct intel_crtc_state *crtc_state) scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX); } -static void -skl_get_initial_plane_config(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - enum plane_id plane_id = plane->id; - enum pipe pipe; - u32 val, base, offset, stride_mult, tiling, alpha; - int fourcc, pixel_format; - unsigned int aligned_height; - struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; - - if (!plane->get_hw_state(plane, &pipe)) - return; - - drm_WARN_ON(dev, pipe != crtc->pipe); - - if (crtc_state->bigjoiner) { - drm_dbg_kms(&dev_priv->drm, - "Unsupported bigjoiner configuration for initial FB\n"); - return; - } - - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) { - drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); - return; - } - - fb = &intel_fb->base; - - fb->dev = dev; - - val = intel_de_read(dev_priv, PLANE_CTL(pipe, plane_id)); - - if (INTEL_GEN(dev_priv) >= 11) - pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK; - else - pixel_format = val & PLANE_CTL_FORMAT_MASK; - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { - alpha = intel_de_read(dev_priv, - PLANE_COLOR_CTL(pipe, plane_id)); - alpha &= PLANE_COLOR_ALPHA_MASK; - } else { - alpha = val & PLANE_CTL_ALPHA_MASK; - } - - fourcc = skl_format_to_fourcc(pixel_format, - val & PLANE_CTL_ORDER_RGBX, alpha); - fb->format = drm_format_info(fourcc); - - tiling = val & PLANE_CTL_TILED_MASK; - switch (tiling) { - case PLANE_CTL_TILED_LINEAR: - fb->modifier = DRM_FORMAT_MOD_LINEAR; - break; - case PLANE_CTL_TILED_X: - plane_config->tiling = I915_TILING_X; - fb->modifier = I915_FORMAT_MOD_X_TILED; - break; - case PLANE_CTL_TILED_Y: - plane_config->tiling = I915_TILING_Y; - if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) - fb->modifier = INTEL_GEN(dev_priv) >= 12 ? - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS : - I915_FORMAT_MOD_Y_TILED_CCS; - else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) - fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; - else - fb->modifier = I915_FORMAT_MOD_Y_TILED; - break; - case PLANE_CTL_TILED_YF: - if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) - fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; - else - fb->modifier = I915_FORMAT_MOD_Yf_TILED; - break; - default: - MISSING_CASE(tiling); - goto error; - } - - /* - * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr - * while i915 HW rotation is clockwise, thats why this swapping. - */ - switch (val & PLANE_CTL_ROTATE_MASK) { - case PLANE_CTL_ROTATE_0: - plane_config->rotation = DRM_MODE_ROTATE_0; - break; - case PLANE_CTL_ROTATE_90: - plane_config->rotation = DRM_MODE_ROTATE_270; - break; - case PLANE_CTL_ROTATE_180: - plane_config->rotation = DRM_MODE_ROTATE_180; - break; - case PLANE_CTL_ROTATE_270: - plane_config->rotation = DRM_MODE_ROTATE_90; - break; - } - - if (INTEL_GEN(dev_priv) >= 10 && - val & PLANE_CTL_FLIP_HORIZONTAL) - plane_config->rotation |= DRM_MODE_REFLECT_X; - - /* 90/270 degree rotation would require extra work */ - if (drm_rotation_90_or_270(plane_config->rotation)) - goto error; - - base = intel_de_read(dev_priv, PLANE_SURF(pipe, plane_id)) & 0xfffff000; - plane_config->base = base; - - offset = intel_de_read(dev_priv, PLANE_OFFSET(pipe, plane_id)); - - val = intel_de_read(dev_priv, PLANE_SIZE(pipe, plane_id)); - fb->height = ((val >> 16) & 0xffff) + 1; - fb->width = ((val >> 0) & 0xffff) + 1; - - val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id)); - stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0); - fb->pitches[0] = (val & 0x3ff) * stride_mult; - - aligned_height = intel_fb_align_height(fb, 0, fb->height); - - plane_config->size = fb->pitches[0] * aligned_height; - - drm_dbg_kms(&dev_priv->drm, - "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - crtc->base.name, plane->base.name, fb->width, fb->height, - fb->format->cpp[0] * 8, base, fb->pitches[0], - plane_config->size); - - plane_config->fb = intel_fb; - return; - -error: - kfree(intel_fb); -} - static void ilk_get_pfit_config(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 64ffa34544a7..251398128349 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -52,6 +52,7 @@ struct intel_crtc_state; struct intel_digital_port; struct intel_dp; struct intel_encoder; +struct intel_initial_plane_config; struct intel_load_detect_pipe; struct intel_plane; struct intel_plane_state; @@ -508,7 +509,6 @@ void intel_link_compute_m_n(u16 bpp, int nlanes, struct intel_link_m_n *m_n, bool constant_n, bool fec_enable); bool is_ccs_modifier(u64 modifier); -int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane); void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv); u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, u32 pixel_format, u64 modifier); @@ -620,18 +620,7 @@ u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set); void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, int id, int set, enum drm_scaling_filter filter); void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state); -u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); -u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state); -u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); -u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state); -u32 skl_plane_stride(const struct intel_plane_state *plane_state, - int plane); -int skl_check_plane_surface(struct intel_plane_state *plane_state); -int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, - int *x, int *y, u32 *offset); -int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); + int bdw_get_pipemisc_bpp(struct intel_crtc *crtc); unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state); @@ -654,6 +643,18 @@ struct intel_encoder * intel_get_crtc_new_encoder(const struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state); +unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, + int color_plane); +void intel_fb_plane_get_subsampling(int *hsub, int *vsub, + const struct drm_framebuffer *fb, + int color_plane); +u32 intel_plane_adjust_aligned_offset(int *x, int *y, + const struct intel_plane_state *state, + int color_plane, + u32 old_offset, u32 new_offset); +unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane); +unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane); + /* modesetting */ void intel_modeset_init_hw(struct drm_i915_private *i915); int intel_modeset_init_noirq(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 39397748b4b0..23a74496c172 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1894,4 +1895,30 @@ static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv, return dev_priv->fdi_pll_freq; } +static inline bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) +{ + if (!is_ccs_modifier(fb->modifier)) + return false; + + return plane >= fb->format->num_planes / 2; +} + +static inline bool is_gen12_ccs_modifier(u64 modifier) +{ + return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; +} + +static inline bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane) +{ + return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane); +} + +static inline bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) +{ + return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC && + plane == 2; +} + #endif /* __INTEL_DISPLAY_TYPES_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 2c365b778f74..3d176edf389b 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -32,6 +32,7 @@ #include "intel_hdmi.h" #include "intel_psr.h" #include "intel_sprite.h" +#include "skl_universal_plane.h" /** * DOC: Panel Self Refresh (PSR/SRD) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 402030251c64..a5b05ec2f232 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -380,212 +380,7 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) return 0; } -static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915) -{ - if (HAS_D12_PLANE_MINIMIZATION(i915)) - return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3); - else - return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5); -} - -bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, - enum plane_id plane_id) -{ - return INTEL_GEN(dev_priv) >= 11 && - icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id); -} - -bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) -{ - return INTEL_GEN(dev_priv) >= 11 && - icl_hdr_plane_mask() & BIT(plane_id); -} - -static void -skl_plane_ratio(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - unsigned int *num, unsigned int *den) -{ - struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - - if (fb->format->cpp[0] == 8) { - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { - *num = 10; - *den = 8; - } else { - *num = 9; - *den = 8; - } - } else { - *num = 1; - *den = 1; - } -} - -static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); - unsigned int num, den; - unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); - - skl_plane_ratio(crtc_state, plane_state, &num, &den); - - /* two pixels per clock on glk+ */ - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - den *= 2; - - return DIV_ROUND_UP(pixel_rate * num, den); -} - -static int skl_plane_max_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - int cpp = fb->format->cpp[color_plane]; - - switch (fb->modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - /* - * Validated limit is 4k, but has 5k should - * work apart from the following features: - * - Ytile (already limited to 4k) - * - FP16 (already limited to 4k) - * - render compression (already limited to 4k) - * - KVMR sprite and cursor (don't care) - * - horizontal panning (TODO verify this) - * - pipe and plane scaling (TODO verify this) - */ - if (cpp == 8) - return 4096; - else - return 5120; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Yf_TILED_CCS: - case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - /* FIXME AUX plane? */ - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - if (cpp == 8) - return 2048; - else - return 4096; - default: - MISSING_CASE(fb->modifier); - return 2048; - } -} - -static int glk_plane_max_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - int cpp = fb->format->cpp[color_plane]; - - switch (fb->modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - if (cpp == 8) - return 4096; - else - return 5120; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Yf_TILED_CCS: - /* FIXME AUX plane? */ - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - if (cpp == 8) - return 2048; - else - return 5120; - default: - MISSING_CASE(fb->modifier); - return 2048; - } -} - -static int icl_plane_min_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - /* Wa_14011264657, Wa_14011050563: gen11+ */ - switch (fb->format->format) { - case DRM_FORMAT_C8: - return 18; - case DRM_FORMAT_RGB565: - return 10; - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_XVYU2101010: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - return 6; - case DRM_FORMAT_NV12: - return 20; - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - return 12; - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - return 4; - default: - return 1; - } -} - -static int icl_plane_max_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - return 5120; -} - -static int skl_plane_max_height(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - return 4096; -} - -static int icl_plane_max_height(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - return 4320; -} - -static unsigned int -skl_plane_max_stride(struct intel_plane *plane, - u32 pixel_format, u64 modifier, - unsigned int rotation) -{ - const struct drm_format_info *info = drm_format_info(pixel_format); - int cpp = info->cpp[0]; - - /* - * "The stride in bytes must not exceed the - * of the size of 8K pixels and 32K bytes." - */ - if (drm_rotation_90_or_270(rotation)) - return min(8192, 32768 / cpp); - else - return min(8192 * cpp, 32768); -} - -static void +void skl_program_scaler(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) @@ -647,317 +442,6 @@ skl_program_scaler(struct intel_plane *plane, (crtc_w << 16) | crtc_h); } -/* Preoffset values for YUV to RGB Conversion */ -#define PREOFF_YUV_TO_RGB_HI 0x1800 -#define PREOFF_YUV_TO_RGB_ME 0x0000 -#define PREOFF_YUV_TO_RGB_LO 0x1800 - -#define ROFF(x) (((x) & 0xffff) << 16) -#define GOFF(x) (((x) & 0xffff) << 0) -#define BOFF(x) (((x) & 0xffff) << 16) - -/* - * Programs the input color space conversion stage for ICL HDR planes. - * Note that it is assumed that this stage always happens after YUV - * range correction. Thus, the input to this stage is assumed to be - * in full-range YCbCr. - */ -static void -icl_program_input_csc(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - enum plane_id plane_id = plane->id; - - static const u16 input_csc_matrix[][9] = { - /* - * BT.601 full range YCbCr -> full range RGB - * The matrix required is : - * [1.000, 0.000, 1.371, - * 1.000, -0.336, -0.698, - * 1.000, 1.732, 0.0000] - */ - [DRM_COLOR_YCBCR_BT601] = { - 0x7AF8, 0x7800, 0x0, - 0x8B28, 0x7800, 0x9AC0, - 0x0, 0x7800, 0x7DD8, - }, - /* - * BT.709 full range YCbCr -> full range RGB - * The matrix required is : - * [1.000, 0.000, 1.574, - * 1.000, -0.187, -0.468, - * 1.000, 1.855, 0.0000] - */ - [DRM_COLOR_YCBCR_BT709] = { - 0x7C98, 0x7800, 0x0, - 0x9EF8, 0x7800, 0xAC00, - 0x0, 0x7800, 0x7ED8, - }, - /* - * BT.2020 full range YCbCr -> full range RGB - * The matrix required is : - * [1.000, 0.000, 1.474, - * 1.000, -0.1645, -0.5713, - * 1.000, 1.8814, 0.0000] - */ - [DRM_COLOR_YCBCR_BT2020] = { - 0x7BC8, 0x7800, 0x0, - 0x8928, 0x7800, 0xAA88, - 0x0, 0x7800, 0x7F10, - }, - }; - const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding]; - - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0), - ROFF(csc[0]) | GOFF(csc[1])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1), - BOFF(csc[2])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2), - ROFF(csc[3]) | GOFF(csc[4])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3), - BOFF(csc[5])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4), - ROFF(csc[6]) | GOFF(csc[7])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5), - BOFF(csc[8])); - - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0), - PREOFF_YUV_TO_RGB_HI); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), - PREOFF_YUV_TO_RGB_ME); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2), - PREOFF_YUV_TO_RGB_LO); - intel_de_write_fw(dev_priv, - PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0); - intel_de_write_fw(dev_priv, - PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0); - intel_de_write_fw(dev_priv, - PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0); -} - -static void -skl_plane_async_flip(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - bool async_flip) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - unsigned long irqflags; - enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; - u32 surf_addr = plane_state->color_plane[0].offset; - u32 plane_ctl = plane_state->ctl; - - plane_ctl |= skl_plane_ctl_crtc(crtc_state); - - if (async_flip) - plane_ctl |= PLANE_CTL_ASYNC_FLIP; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -static void -skl_program_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; - const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 surf_addr = plane_state->color_plane[color_plane].offset; - u32 stride = skl_plane_stride(plane_state, color_plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; - int aux_plane = intel_main_to_aux_plane(fb, color_plane); - int crtc_x = plane_state->uapi.dst.x1; - int crtc_y = plane_state->uapi.dst.y1; - u32 x = plane_state->color_plane[color_plane].x; - u32 y = plane_state->color_plane[color_plane].y; - u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; - u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; - u8 alpha = plane_state->hw.alpha >> 8; - u32 plane_color_ctl = 0, aux_dist = 0; - unsigned long irqflags; - u32 keymsk, keymax; - u32 plane_ctl = plane_state->ctl; - - plane_ctl |= skl_plane_ctl_crtc(crtc_state); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - plane_color_ctl = plane_state->color_ctl | - glk_plane_color_ctl_crtc(crtc_state); - - /* Sizes are 0 based */ - src_w--; - src_h--; - - keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha); - - keymsk = key->channel_mask & 0x7ffffff; - if (alpha < 0xff) - keymsk |= PLANE_KEYMSK_ALPHA_ENABLE; - - /* The scaler will handle the output position */ - if (plane_state->scaler_id >= 0) { - crtc_x = 0; - crtc_y = 0; - } - - if (aux_plane) { - aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr; - - if (INTEL_GEN(dev_priv) < 12) - aux_dist |= skl_plane_stride(plane_state, aux_plane); - } - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride); - intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id), - (crtc_y << 16) | crtc_x); - intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id), - (src_h << 16) | src_w); - - intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist); - - if (icl_is_hdr_plane(dev_priv, plane_id)) - intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), - plane_state->cus_ctl); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), - plane_color_ctl); - - if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id)) - icl_program_input_csc(plane, crtc_state, plane_state); - - if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC) - intel_uncore_write64_fw(&dev_priv->uncore, - PLANE_CC_VAL(pipe, plane_id), plane_state->ccval); - - skl_write_plane_wm(plane, crtc_state); - - intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), - key->min_value); - intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), keymsk); - intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), keymax); - - intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), - (y << 16) | x); - - if (INTEL_GEN(dev_priv) < 11) - intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), - (plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x); - - if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) - intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); - - /* - * The control register self-arms if the plane was previously - * disabled. Try to make the plane enable atomic by writing - * the control register just before the surface register. - */ - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); - - if (plane_state->scaler_id >= 0) - skl_program_scaler(plane, crtc_state, plane_state); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -static void -skl_update_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - int color_plane = 0; - - if (plane_state->planar_linked_plane && !plane_state->planar_slave) - /* Program the UV plane on planar master */ - color_plane = 1; - - skl_program_plane(plane, crtc_state, plane_state, color_plane); -} -static void -skl_disable_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - if (icl_is_hdr_plane(dev_priv, plane_id)) - intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0); - - skl_write_plane_wm(plane, crtc_state); - - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -static bool -skl_plane_get_hw_state(struct intel_plane *plane, - enum pipe *pipe) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum intel_display_power_domain power_domain; - enum plane_id plane_id = plane->id; - intel_wakeref_t wakeref; - bool ret; - - power_domain = POWER_DOMAIN_PIPE(plane->pipe); - wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); - if (!wakeref) - return false; - - ret = intel_de_read(dev_priv, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE; - - *pipe = plane->pipe; - - intel_display_power_put(dev_priv, power_domain, wakeref); - - return ret; -} - -static void -skl_plane_enable_flip_done(struct intel_plane *plane) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - spin_lock_irq(&i915->irq_lock); - bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); - spin_unlock_irq(&i915->irq_lock); -} - -static void -skl_plane_disable_flip_done(struct intel_plane *plane) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - spin_lock_irq(&i915->irq_lock); - bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); - spin_unlock_irq(&i915->irq_lock); -} - static void i9xx_plane_linear_gamma(u16 gamma[8]) { /* The points are not evenly spaced. */ @@ -2301,253 +1785,19 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state, return 0; } -static bool intel_format_is_p01x(u32 format) +static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) { - switch (format) { - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - return true; - default: - return false; - } + return INTEL_GEN(dev_priv) >= 9; } -static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static void intel_plane_set_ckey(struct intel_plane_state *plane_state, + const struct drm_intel_sprite_colorkey *set) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - struct drm_format_name_buf format_name; + struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - if (!fb) - return 0; - - if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) && - is_ccs_modifier(fb->modifier)) { - drm_dbg_kms(&dev_priv->drm, - "RC support only with 0/180 degree rotation (%x)\n", - rotation); - return -EINVAL; - } - - if (rotation & DRM_MODE_REFLECT_X && - fb->modifier == DRM_FORMAT_MOD_LINEAR) { - drm_dbg_kms(&dev_priv->drm, - "horizontal flip is not supported with linear surface formats\n"); - return -EINVAL; - } - - if (drm_rotation_90_or_270(rotation)) { - if (fb->modifier != I915_FORMAT_MOD_Y_TILED && - fb->modifier != I915_FORMAT_MOD_Yf_TILED) { - drm_dbg_kms(&dev_priv->drm, - "Y/Yf tiling required for 90/270!\n"); - return -EINVAL; - } - - /* - * 90/270 is not allowed with RGB64 16:16:16:16 and - * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards. - */ - switch (fb->format->format) { - case DRM_FORMAT_RGB565: - if (INTEL_GEN(dev_priv) >= 11) - break; - fallthrough; - case DRM_FORMAT_C8: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - drm_dbg_kms(&dev_priv->drm, - "Unsupported pixel format %s for 90/270!\n", - drm_get_format_name(fb->format->format, - &format_name)); - return -EINVAL; - default: - break; - } - } - - /* Y-tiling is not supported in IF-ID Interlace mode */ - if (crtc_state->hw.enable && - crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE && - (fb->modifier == I915_FORMAT_MOD_Y_TILED || - fb->modifier == I915_FORMAT_MOD_Yf_TILED || - fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) { - drm_dbg_kms(&dev_priv->drm, - "Y/Yf tiling not supported in IF-ID mode\n"); - return -EINVAL; - } - - /* Wa_1606054188:tgl,adl-s */ - if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) && - plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE && - intel_format_is_p01x(fb->format->format)) { - drm_dbg_kms(&dev_priv->drm, - "Source color keying not supported with P01x formats\n"); - return -EINVAL; - } - - return 0; -} - -static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); - int crtc_x = plane_state->uapi.dst.x1; - int crtc_w = drm_rect_width(&plane_state->uapi.dst); - int pipe_src_w = crtc_state->pipe_src_w; - - /* - * Display WA #1175: cnl,glk - * Planes other than the cursor may cause FIFO underflow and display - * corruption if starting less than 4 pixels from the right edge of - * the screen. - * Besides the above WA fix the similar problem, where planes other - * than the cursor ending less than 4 pixels from the left edge of the - * screen may cause FIFO underflow and display corruption. - */ - if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && - (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) { - drm_dbg_kms(&dev_priv->drm, - "requested plane X %s position %d invalid (valid range %d-%d)\n", - crtc_x + crtc_w < 4 ? "end" : "start", - crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x, - 4, pipe_src_w - 4); - return -ERANGE; - } - - return 0; -} - -static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; - - /* Display WA #1106 */ - if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && - src_w & 3 && - (rotation == DRM_MODE_ROTATE_270 || - rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) { - DRM_DEBUG_KMS("src width must be multiple of 4 for rotated planar YUV\n"); - return -EINVAL; - } - - return 0; -} - -static int skl_plane_max_scale(struct drm_i915_private *dev_priv, - const struct drm_framebuffer *fb) -{ - /* - * We don't yet know the final source width nor - * whether we can use the HQ scaler mode. Assume - * the best case. - * FIXME need to properly check this later. - */ - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) || - !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - return 0x30000 - 1; - else - return 0x20000 - 1; -} - -static int skl_plane_check(struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; - int ret; - - ret = skl_plane_check_fb(crtc_state, plane_state); - if (ret) - return ret; - - /* use scaler when colorkey is not required */ - if (!plane_state->ckey.flags && intel_fb_scalable(fb)) { - min_scale = 1; - max_scale = skl_plane_max_scale(dev_priv, fb); - } - - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - min_scale, max_scale, true); - if (ret) - return ret; - - ret = skl_check_plane_surface(plane_state); - if (ret) - return ret; - - if (!plane_state->uapi.visible) - return 0; - - ret = skl_plane_check_dst_coordinates(crtc_state, plane_state); - if (ret) - return ret; - - ret = intel_plane_check_src_coordinates(plane_state); - if (ret) - return ret; - - ret = skl_plane_check_nv12_rotation(plane_state); - if (ret) - return ret; - - /* HW only has 8 bits pixel precision, disable plane if invisible */ - if (!(plane_state->hw.alpha >> 8)) - plane_state->uapi.visible = false; - - plane_state->ctl = skl_plane_ctl(crtc_state, plane_state); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - plane_state->color_ctl = glk_plane_color_ctl(crtc_state, - plane_state); - - if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && - icl_is_hdr_plane(dev_priv, plane->id)) - /* Enable and use MPEG-2 chroma siting */ - plane_state->cus_ctl = PLANE_CUS_ENABLE | - PLANE_CUS_HPHASE_0 | - PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25; - else - plane_state->cus_ctl = 0; - - return 0; -} - -static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) -{ - return INTEL_GEN(dev_priv) >= 9; -} - -static void intel_plane_set_ckey(struct intel_plane_state *plane_state, - const struct drm_intel_sprite_colorkey *set) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - - *key = *set; + *key = *set; /* * We want src key enabled on the @@ -2712,186 +1962,6 @@ static const u32 chv_pipe_b_sprite_formats[] = { DRM_FORMAT_VYUY, }; -static const u32 skl_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_XYUV8888, -}; - -static const u32 skl_planar_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_XYUV8888, -}; - -static const u32 glk_planar_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_P010, - DRM_FORMAT_P012, - DRM_FORMAT_P016, -}; - -static const u32 icl_sdr_y_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_ABGR2101010, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, - DRM_FORMAT_Y216, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_XVYU2101010, - DRM_FORMAT_XVYU12_16161616, - DRM_FORMAT_XVYU16161616, -}; - -static const u32 icl_sdr_uv_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_ABGR2101010, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_P010, - DRM_FORMAT_P012, - DRM_FORMAT_P016, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, - DRM_FORMAT_Y216, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_XVYU2101010, - DRM_FORMAT_XVYU12_16161616, - DRM_FORMAT_XVYU16161616, -}; - -static const u32 icl_hdr_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_ABGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_ARGB16161616F, - DRM_FORMAT_ABGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_P010, - DRM_FORMAT_P012, - DRM_FORMAT_P016, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, - DRM_FORMAT_Y216, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_XVYU2101010, - DRM_FORMAT_XVYU12_16161616, - DRM_FORMAT_XVYU16161616, -}; - -static const u64 skl_plane_format_modifiers_noccs[] = { - I915_FORMAT_MOD_Yf_TILED, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static const u64 skl_plane_format_modifiers_ccs[] = { - I915_FORMAT_MOD_Yf_TILED_CCS, - I915_FORMAT_MOD_Y_TILED_CCS, - I915_FORMAT_MOD_Yf_TILED, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static const u64 gen12_plane_format_modifiers_mc_ccs[] = { - I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static const u64 gen12_plane_format_modifiers_rc_ccs[] = { - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane, u32 format, u64 modifier) { @@ -2984,150 +2054,6 @@ static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane, } } -static bool skl_plane_format_mod_supported(struct drm_plane *_plane, - u32 format, u64 modifier) -{ - struct intel_plane *plane = to_intel_plane(_plane); - - switch (modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - break; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Yf_TILED_CCS: - if (!plane->has_ccs) - return false; - break; - default: - return false; - } - - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - if (is_ccs_modifier(modifier)) - return true; - fallthrough; - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_XYUV8888: - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - case DRM_FORMAT_XVYU2101010: - if (modifier == I915_FORMAT_MOD_Yf_TILED) - return true; - fallthrough; - case DRM_FORMAT_C8: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - if (modifier == DRM_FORMAT_MOD_LINEAR || - modifier == I915_FORMAT_MOD_X_TILED || - modifier == I915_FORMAT_MOD_Y_TILED) - return true; - fallthrough; - default: - return false; - } -} - -static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, - enum plane_id plane_id) -{ - /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */ - if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) || - IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0)) - return false; - - return plane_id < PLANE_SPRITE4; -} - -static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, - u32 format, u64 modifier) -{ - struct drm_i915_private *dev_priv = to_i915(_plane->dev); - struct intel_plane *plane = to_intel_plane(_plane); - - switch (modifier) { - case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id)) - return false; - fallthrough; - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: - break; - default: - return false; - } - - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - if (is_ccs_modifier(modifier)) - return true; - fallthrough; - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_XYUV8888: - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) - return true; - fallthrough; - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_XVYU2101010: - case DRM_FORMAT_C8: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - if (modifier == DRM_FORMAT_MOD_LINEAR || - modifier == I915_FORMAT_MOD_X_TILED || - modifier == I915_FORMAT_MOD_Y_TILED) - return true; - fallthrough; - default: - return false; - } -} - static const struct drm_plane_funcs g4x_sprite_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -3155,257 +2081,6 @@ static const struct drm_plane_funcs vlv_sprite_funcs = { .format_mod_supported = vlv_sprite_format_mod_supported, }; -static const struct drm_plane_funcs skl_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = skl_plane_format_mod_supported, -}; - -static const struct drm_plane_funcs gen12_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = gen12_plane_format_mod_supported, -}; - -static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - if (!HAS_FBC(dev_priv)) - return false; - - return pipe == PIPE_A && plane_id == PLANE_PRIMARY; -} - -static bool skl_plane_has_planar(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - /* Display WA #0870: skl, bxt */ - if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) - return false; - - if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) - return false; - - if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) - return false; - - return true; -} - -static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id, - int *num_formats) -{ - if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { - *num_formats = ARRAY_SIZE(skl_planar_formats); - return skl_planar_formats; - } else { - *num_formats = ARRAY_SIZE(skl_plane_formats); - return skl_plane_formats; - } -} - -static const u32 *glk_get_plane_formats(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id, - int *num_formats) -{ - if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { - *num_formats = ARRAY_SIZE(glk_planar_formats); - return glk_planar_formats; - } else { - *num_formats = ARRAY_SIZE(skl_plane_formats); - return skl_plane_formats; - } -} - -static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id, - int *num_formats) -{ - if (icl_is_hdr_plane(dev_priv, plane_id)) { - *num_formats = ARRAY_SIZE(icl_hdr_plane_formats); - return icl_hdr_plane_formats; - } else if (icl_is_nv12_y_plane(dev_priv, plane_id)) { - *num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats); - return icl_sdr_y_plane_formats; - } else { - *num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats); - return icl_sdr_uv_plane_formats; - } -} - -static const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv, - enum plane_id plane_id) -{ - if (gen12_plane_supports_mc_ccs(dev_priv, plane_id)) - return gen12_plane_format_modifiers_mc_ccs; - else - return gen12_plane_format_modifiers_rc_ccs; -} - -static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - if (plane_id == PLANE_CURSOR) - return false; - - if (INTEL_GEN(dev_priv) >= 10) - return true; - - if (IS_GEMINILAKE(dev_priv)) - return pipe != PIPE_C; - - return pipe != PIPE_C && - (plane_id == PLANE_PRIMARY || - plane_id == PLANE_SPRITE0); -} - -struct intel_plane * -skl_universal_plane_create(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - const struct drm_plane_funcs *plane_funcs; - struct intel_plane *plane; - enum drm_plane_type plane_type; - unsigned int supported_rotations; - unsigned int supported_csc; - const u64 *modifiers; - const u32 *formats; - int num_formats; - int ret; - - plane = intel_plane_alloc(); - if (IS_ERR(plane)) - return plane; - - plane->pipe = pipe; - plane->id = plane_id; - plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id); - - plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id); - if (plane->has_fbc) { - struct intel_fbc *fbc = &dev_priv->fbc; - - fbc->possible_framebuffer_bits |= plane->frontbuffer_bit; - } - - if (INTEL_GEN(dev_priv) >= 11) { - plane->min_width = icl_plane_min_width; - plane->max_width = icl_plane_max_width; - plane->max_height = icl_plane_max_height; - } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { - plane->max_width = glk_plane_max_width; - plane->max_height = skl_plane_max_height; - } else { - plane->max_width = skl_plane_max_width; - plane->max_height = skl_plane_max_height; - } - - plane->max_stride = skl_plane_max_stride; - plane->update_plane = skl_update_plane; - plane->disable_plane = skl_disable_plane; - plane->get_hw_state = skl_plane_get_hw_state; - plane->check_plane = skl_plane_check; - plane->min_cdclk = skl_plane_min_cdclk; - - if (plane_id == PLANE_PRIMARY) { - plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 9, 10); - plane->async_flip = skl_plane_async_flip; - plane->enable_flip_done = skl_plane_enable_flip_done; - plane->disable_flip_done = skl_plane_disable_flip_done; - } - - if (INTEL_GEN(dev_priv) >= 11) - formats = icl_get_plane_formats(dev_priv, pipe, - plane_id, &num_formats); - else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - formats = glk_get_plane_formats(dev_priv, pipe, - plane_id, &num_formats); - else - formats = skl_get_plane_formats(dev_priv, pipe, - plane_id, &num_formats); - - plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id); - if (INTEL_GEN(dev_priv) >= 12) { - modifiers = gen12_get_plane_modifiers(dev_priv, plane_id); - plane_funcs = &gen12_plane_funcs; - } else { - if (plane->has_ccs) - modifiers = skl_plane_format_modifiers_ccs; - else - modifiers = skl_plane_format_modifiers_noccs; - plane_funcs = &skl_plane_funcs; - } - - if (plane_id == PLANE_PRIMARY) - plane_type = DRM_PLANE_TYPE_PRIMARY; - else - plane_type = DRM_PLANE_TYPE_OVERLAY; - - ret = drm_universal_plane_init(&dev_priv->drm, &plane->base, - 0, plane_funcs, - formats, num_formats, modifiers, - plane_type, - "plane %d%c", plane_id + 1, - pipe_name(pipe)); - if (ret) - goto fail; - - supported_rotations = - DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | - DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; - - if (INTEL_GEN(dev_priv) >= 10) - supported_rotations |= DRM_MODE_REFLECT_X; - - drm_plane_create_rotation_property(&plane->base, - DRM_MODE_ROTATE_0, - supported_rotations); - - supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020); - - drm_plane_create_color_properties(&plane->base, - supported_csc, - BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | - BIT(DRM_COLOR_YCBCR_FULL_RANGE), - DRM_COLOR_YCBCR_BT709, - DRM_COLOR_YCBCR_LIMITED_RANGE); - - drm_plane_create_alpha_property(&plane->base); - drm_plane_create_blend_mode_property(&plane->base, - BIT(DRM_MODE_BLEND_PIXEL_NONE) | - BIT(DRM_MODE_BLEND_PREMULTI) | - BIT(DRM_MODE_BLEND_COVERAGE)); - - drm_plane_create_zpos_immutable_property(&plane->base, plane_id); - - if (INTEL_GEN(dev_priv) >= 12) - drm_plane_enable_fb_damage_clips(&plane->base); - - if (INTEL_GEN(dev_priv) >= 10) - drm_plane_create_scaling_filter_property(&plane->base, - BIT(DRM_SCALING_FILTER_DEFAULT) | - BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); - - drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); - - return plane; - -fail: - intel_plane_free(plane); - - return ERR_PTR(ret); -} - struct intel_plane * intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int sprite) @@ -3418,10 +2093,6 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, int num_formats; int ret, zpos; - if (INTEL_GEN(dev_priv) >= 9) - return skl_universal_plane_create(dev_priv, pipe, - PLANE_SPRITE0 + sprite); - plane = intel_plane_alloc(); if (IS_ERR(plane)) return plane; diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 76126dd8d584..418897f953fc 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -38,9 +38,6 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state); int intel_plane_check_stride(const struct intel_plane_state *plane_state); int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state); int chv_plane_check_rotation(const struct intel_plane_state *plane_state); -struct intel_plane * -skl_universal_plane_create(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id); static inline u8 icl_hdr_plane_mask(void) { @@ -59,4 +56,7 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); +void skl_program_scaler(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state); #endif /* __INTEL_SPRITE_H__ */ diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c new file mode 100644 index 000000000000..29c2e3693e8b --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -0,0 +1,2265 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ + +#include +#include +#include +#include + +#include "i915_drv.h" +#include "intel_atomic_plane.h" +#include "intel_display_types.h" +#include "intel_pm.h" +#include "intel_psr.h" +#include "intel_sprite.h" +#include "skl_universal_plane.h" + +static const u32 skl_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_XYUV8888, +}; + +static const u32 skl_planar_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_XYUV8888, +}; + +static const u32 glk_planar_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_P010, + DRM_FORMAT_P012, + DRM_FORMAT_P016, +}; + +static const u32 icl_sdr_y_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_Y210, + DRM_FORMAT_Y212, + DRM_FORMAT_Y216, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XVYU2101010, + DRM_FORMAT_XVYU12_16161616, + DRM_FORMAT_XVYU16161616, +}; + +static const u32 icl_sdr_uv_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_P010, + DRM_FORMAT_P012, + DRM_FORMAT_P016, + DRM_FORMAT_Y210, + DRM_FORMAT_Y212, + DRM_FORMAT_Y216, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XVYU2101010, + DRM_FORMAT_XVYU12_16161616, + DRM_FORMAT_XVYU16161616, +}; + +static const u32 icl_hdr_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_ARGB16161616F, + DRM_FORMAT_ABGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_P010, + DRM_FORMAT_P012, + DRM_FORMAT_P016, + DRM_FORMAT_Y210, + DRM_FORMAT_Y212, + DRM_FORMAT_Y216, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XVYU2101010, + DRM_FORMAT_XVYU12_16161616, + DRM_FORMAT_XVYU16161616, +}; + +static const u64 skl_plane_format_modifiers_noccs[] = { + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 skl_plane_format_modifiers_ccs[] = { + I915_FORMAT_MOD_Yf_TILED_CCS, + I915_FORMAT_MOD_Y_TILED_CCS, + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 gen12_plane_format_modifiers_mc_ccs[] = { + I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 gen12_plane_format_modifiers_rc_ccs[] = { + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) +{ + switch (format) { + case PLANE_CTL_FORMAT_RGB_565: + return DRM_FORMAT_RGB565; + case PLANE_CTL_FORMAT_NV12: + return DRM_FORMAT_NV12; + case PLANE_CTL_FORMAT_XYUV: + return DRM_FORMAT_XYUV8888; + case PLANE_CTL_FORMAT_P010: + return DRM_FORMAT_P010; + case PLANE_CTL_FORMAT_P012: + return DRM_FORMAT_P012; + case PLANE_CTL_FORMAT_P016: + return DRM_FORMAT_P016; + case PLANE_CTL_FORMAT_Y210: + return DRM_FORMAT_Y210; + case PLANE_CTL_FORMAT_Y212: + return DRM_FORMAT_Y212; + case PLANE_CTL_FORMAT_Y216: + return DRM_FORMAT_Y216; + case PLANE_CTL_FORMAT_Y410: + return DRM_FORMAT_XVYU2101010; + case PLANE_CTL_FORMAT_Y412: + return DRM_FORMAT_XVYU12_16161616; + case PLANE_CTL_FORMAT_Y416: + return DRM_FORMAT_XVYU16161616; + default: + case PLANE_CTL_FORMAT_XRGB_8888: + if (rgb_order) { + if (alpha) + return DRM_FORMAT_ABGR8888; + else + return DRM_FORMAT_XBGR8888; + } else { + if (alpha) + return DRM_FORMAT_ARGB8888; + else + return DRM_FORMAT_XRGB8888; + } + case PLANE_CTL_FORMAT_XRGB_2101010: + if (rgb_order) { + if (alpha) + return DRM_FORMAT_ABGR2101010; + else + return DRM_FORMAT_XBGR2101010; + } else { + if (alpha) + return DRM_FORMAT_ARGB2101010; + else + return DRM_FORMAT_XRGB2101010; + } + case PLANE_CTL_FORMAT_XRGB_16161616F: + if (rgb_order) { + if (alpha) + return DRM_FORMAT_ABGR16161616F; + else + return DRM_FORMAT_XBGR16161616F; + } else { + if (alpha) + return DRM_FORMAT_ARGB16161616F; + else + return DRM_FORMAT_XRGB16161616F; + } + } +} + +static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915) +{ + if (HAS_D12_PLANE_MINIMIZATION(i915)) + return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3); + else + return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5); +} + +bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, + enum plane_id plane_id) +{ + return INTEL_GEN(dev_priv) >= 11 && + icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id); +} + +bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) +{ + return INTEL_GEN(dev_priv) >= 11 && + icl_hdr_plane_mask() & BIT(plane_id); +} + +static void +skl_plane_ratio(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + unsigned int *num, unsigned int *den) +{ + struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + + if (fb->format->cpp[0] == 8) { + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + *num = 10; + *den = 8; + } else { + *num = 9; + *den = 8; + } + } else { + *num = 1; + *den = 1; + } +} + +static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); + unsigned int num, den; + unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); + + skl_plane_ratio(crtc_state, plane_state, &num, &den); + + /* two pixels per clock on glk+ */ + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + den *= 2; + + return DIV_ROUND_UP(pixel_rate * num, den); +} + +static int skl_plane_max_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + int cpp = fb->format->cpp[color_plane]; + + switch (fb->modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + /* + * Validated limit is 4k, but has 5k should + * work apart from the following features: + * - Ytile (already limited to 4k) + * - FP16 (already limited to 4k) + * - render compression (already limited to 4k) + * - KVMR sprite and cursor (don't care) + * - horizontal panning (TODO verify this) + * - pipe and plane scaling (TODO verify this) + */ + if (cpp == 8) + return 4096; + else + return 5120; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + /* FIXME AUX plane? */ + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + if (cpp == 8) + return 2048; + else + return 4096; + default: + MISSING_CASE(fb->modifier); + return 2048; + } +} + +static int glk_plane_max_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + int cpp = fb->format->cpp[color_plane]; + + switch (fb->modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + if (cpp == 8) + return 4096; + else + return 5120; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + /* FIXME AUX plane? */ + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + if (cpp == 8) + return 2048; + else + return 5120; + default: + MISSING_CASE(fb->modifier); + return 2048; + } +} + +static int icl_plane_min_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + /* Wa_14011264657, Wa_14011050563: gen11+ */ + switch (fb->format->format) { + case DRM_FORMAT_C8: + return 18; + case DRM_FORMAT_RGB565: + return 10; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + return 6; + case DRM_FORMAT_NV12: + return 20; + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + return 12; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + return 4; + default: + return 1; + } +} + +static int icl_plane_max_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + return 5120; +} + +static int skl_plane_max_height(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + return 4096; +} + +static int icl_plane_max_height(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + return 4320; +} + +static unsigned int +skl_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + const struct drm_format_info *info = drm_format_info(pixel_format); + int cpp = info->cpp[0]; + + /* + * "The stride in bytes must not exceed the + * of the size of 8K pixels and 32K bytes." + */ + if (drm_rotation_90_or_270(rotation)) + return min(8192, 32768 / cpp); + else + return min(8192 * cpp, 32768); +} + + +/* Preoffset values for YUV to RGB Conversion */ +#define PREOFF_YUV_TO_RGB_HI 0x1800 +#define PREOFF_YUV_TO_RGB_ME 0x0000 +#define PREOFF_YUV_TO_RGB_LO 0x1800 + +#define ROFF(x) (((x) & 0xffff) << 16) +#define GOFF(x) (((x) & 0xffff) << 0) +#define BOFF(x) (((x) & 0xffff) << 16) + +/* + * Programs the input color space conversion stage for ICL HDR planes. + * Note that it is assumed that this stage always happens after YUV + * range correction. Thus, the input to this stage is assumed to be + * in full-range YCbCr. + */ +static void +icl_program_input_csc(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + enum plane_id plane_id = plane->id; + + static const u16 input_csc_matrix[][9] = { + /* + * BT.601 full range YCbCr -> full range RGB + * The matrix required is : + * [1.000, 0.000, 1.371, + * 1.000, -0.336, -0.698, + * 1.000, 1.732, 0.0000] + */ + [DRM_COLOR_YCBCR_BT601] = { + 0x7AF8, 0x7800, 0x0, + 0x8B28, 0x7800, 0x9AC0, + 0x0, 0x7800, 0x7DD8, + }, + /* + * BT.709 full range YCbCr -> full range RGB + * The matrix required is : + * [1.000, 0.000, 1.574, + * 1.000, -0.187, -0.468, + * 1.000, 1.855, 0.0000] + */ + [DRM_COLOR_YCBCR_BT709] = { + 0x7C98, 0x7800, 0x0, + 0x9EF8, 0x7800, 0xAC00, + 0x0, 0x7800, 0x7ED8, + }, + /* + * BT.2020 full range YCbCr -> full range RGB + * The matrix required is : + * [1.000, 0.000, 1.474, + * 1.000, -0.1645, -0.5713, + * 1.000, 1.8814, 0.0000] + */ + [DRM_COLOR_YCBCR_BT2020] = { + 0x7BC8, 0x7800, 0x0, + 0x8928, 0x7800, 0xAA88, + 0x0, 0x7800, 0x7F10, + }, + }; + const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding]; + + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0), + ROFF(csc[0]) | GOFF(csc[1])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1), + BOFF(csc[2])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2), + ROFF(csc[3]) | GOFF(csc[4])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3), + BOFF(csc[5])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4), + ROFF(csc[6]) | GOFF(csc[7])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5), + BOFF(csc[8])); + + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0), + PREOFF_YUV_TO_RGB_HI); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), + PREOFF_YUV_TO_RGB_ME); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2), + PREOFF_YUV_TO_RGB_LO); + intel_de_write_fw(dev_priv, + PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0); + intel_de_write_fw(dev_priv, + PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0); + intel_de_write_fw(dev_priv, + PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0); +} + +static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane) +{ + return fb->modifier == DRM_FORMAT_MOD_LINEAR || + is_gen12_ccs_plane(fb, color_plane); +} + +static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb, + int color_plane, unsigned int rotation) +{ + /* + * The stride is either expressed as a multiple of 64 bytes chunks for + * linear buffers or in number of tiles for tiled buffers. + */ + if (is_surface_linear(fb, color_plane)) + return 64; + else if (drm_rotation_90_or_270(rotation)) + return intel_tile_height(fb, color_plane); + else + return intel_tile_width_bytes(fb, color_plane); +} + +static u32 skl_plane_stride(const struct intel_plane_state *plane_state, + int color_plane) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + u32 stride = plane_state->color_plane[color_plane].stride; + + if (color_plane >= fb->format->num_planes) + return 0; + + return stride / skl_plane_stride_mult(fb, color_plane, rotation); +} + +static void +skl_disable_plane(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + if (icl_is_hdr_plane(dev_priv, plane_id)) + intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0); + + skl_write_plane_wm(plane, crtc_state); + + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static bool +skl_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum intel_display_power_domain power_domain; + enum plane_id plane_id = plane->id; + intel_wakeref_t wakeref; + bool ret; + + power_domain = POWER_DOMAIN_PIPE(plane->pipe); + wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); + if (!wakeref) + return false; + + ret = intel_de_read(dev_priv, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE; + + *pipe = plane->pipe; + + intel_display_power_put(dev_priv, power_domain, wakeref); + + return ret; +} + +static u32 skl_plane_ctl_format(u32 pixel_format) +{ + switch (pixel_format) { + case DRM_FORMAT_C8: + return PLANE_CTL_FORMAT_INDEXED; + case DRM_FORMAT_RGB565: + return PLANE_CTL_FORMAT_RGB_565; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + return PLANE_CTL_FORMAT_XRGB_8888; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + return PLANE_CTL_FORMAT_XRGB_2101010; + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + return PLANE_CTL_FORMAT_XRGB_16161616F; + case DRM_FORMAT_XYUV8888: + return PLANE_CTL_FORMAT_XYUV; + case DRM_FORMAT_YUYV: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; + case DRM_FORMAT_YVYU: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; + case DRM_FORMAT_UYVY: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; + case DRM_FORMAT_VYUY: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; + case DRM_FORMAT_NV12: + return PLANE_CTL_FORMAT_NV12; + case DRM_FORMAT_P010: + return PLANE_CTL_FORMAT_P010; + case DRM_FORMAT_P012: + return PLANE_CTL_FORMAT_P012; + case DRM_FORMAT_P016: + return PLANE_CTL_FORMAT_P016; + case DRM_FORMAT_Y210: + return PLANE_CTL_FORMAT_Y210; + case DRM_FORMAT_Y212: + return PLANE_CTL_FORMAT_Y212; + case DRM_FORMAT_Y216: + return PLANE_CTL_FORMAT_Y216; + case DRM_FORMAT_XVYU2101010: + return PLANE_CTL_FORMAT_Y410; + case DRM_FORMAT_XVYU12_16161616: + return PLANE_CTL_FORMAT_Y412; + case DRM_FORMAT_XVYU16161616: + return PLANE_CTL_FORMAT_Y416; + default: + MISSING_CASE(pixel_format); + } + + return 0; +} + +static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state) +{ + if (!plane_state->hw.fb->format->has_alpha) + return PLANE_CTL_ALPHA_DISABLE; + + switch (plane_state->hw.pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return PLANE_CTL_ALPHA_DISABLE; + case DRM_MODE_BLEND_PREMULTI: + return PLANE_CTL_ALPHA_SW_PREMULTIPLY; + case DRM_MODE_BLEND_COVERAGE: + return PLANE_CTL_ALPHA_HW_PREMULTIPLY; + default: + MISSING_CASE(plane_state->hw.pixel_blend_mode); + return PLANE_CTL_ALPHA_DISABLE; + } +} + +static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state) +{ + if (!plane_state->hw.fb->format->has_alpha) + return PLANE_COLOR_ALPHA_DISABLE; + + switch (plane_state->hw.pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return PLANE_COLOR_ALPHA_DISABLE; + case DRM_MODE_BLEND_PREMULTI: + return PLANE_COLOR_ALPHA_SW_PREMULTIPLY; + case DRM_MODE_BLEND_COVERAGE: + return PLANE_COLOR_ALPHA_HW_PREMULTIPLY; + default: + MISSING_CASE(plane_state->hw.pixel_blend_mode); + return PLANE_COLOR_ALPHA_DISABLE; + } +} + +static u32 skl_plane_ctl_tiling(u64 fb_modifier) +{ + switch (fb_modifier) { + case DRM_FORMAT_MOD_LINEAR: + break; + case I915_FORMAT_MOD_X_TILED: + return PLANE_CTL_TILED_X; + case I915_FORMAT_MOD_Y_TILED: + return PLANE_CTL_TILED_Y; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: + return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: + return PLANE_CTL_TILED_Y | + PLANE_CTL_RENDER_DECOMPRESSION_ENABLE | + PLANE_CTL_CLEAR_COLOR_DISABLE; + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE; + case I915_FORMAT_MOD_Yf_TILED: + return PLANE_CTL_TILED_YF; + case I915_FORMAT_MOD_Yf_TILED_CCS: + return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; + default: + MISSING_CASE(fb_modifier); + } + + return 0; +} + +static u32 skl_plane_ctl_rotate(unsigned int rotate) +{ + switch (rotate) { + case DRM_MODE_ROTATE_0: + break; + /* + * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr + * while i915 HW rotation is clockwise, thats why this swapping. + */ + case DRM_MODE_ROTATE_90: + return PLANE_CTL_ROTATE_270; + case DRM_MODE_ROTATE_180: + return PLANE_CTL_ROTATE_180; + case DRM_MODE_ROTATE_270: + return PLANE_CTL_ROTATE_90; + default: + MISSING_CASE(rotate); + } + + return 0; +} + +static u32 cnl_plane_ctl_flip(unsigned int reflect) +{ + switch (reflect) { + case 0: + break; + case DRM_MODE_REFLECT_X: + return PLANE_CTL_FLIP_HORIZONTAL; + case DRM_MODE_REFLECT_Y: + default: + MISSING_CASE(reflect); + } + + return 0; +} + +static u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + u32 plane_ctl = 0; + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + return plane_ctl; + + if (crtc_state->gamma_enable) + plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE; + + if (crtc_state->csc_enable) + plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE; + + return plane_ctl; +} + +static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; + u32 plane_ctl; + + plane_ctl = PLANE_CTL_ENABLE; + + if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { + plane_ctl |= skl_plane_ctl_alpha(plane_state); + plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; + + if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709) + plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709; + + if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE; + } + + plane_ctl |= skl_plane_ctl_format(fb->format->format); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier); + plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK); + + if (INTEL_GEN(dev_priv) >= 10) + plane_ctl |= cnl_plane_ctl_flip(rotation & + DRM_MODE_REFLECT_MASK); + + if (key->flags & I915_SET_COLORKEY_DESTINATION) + plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; + + return plane_ctl; +} + +static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + u32 plane_color_ctl = 0; + + if (INTEL_GEN(dev_priv) >= 11) + return plane_color_ctl; + + if (crtc_state->gamma_enable) + plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE; + + if (crtc_state->csc_enable) + plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE; + + return plane_color_ctl; +} + +static u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + u32 plane_color_ctl = 0; + + plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; + plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state); + + if (fb->format->is_yuv && !icl_is_hdr_plane(dev_priv, plane->id)) { + switch (plane_state->hw.color_encoding) { + case DRM_COLOR_YCBCR_BT709: + plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; + break; + case DRM_COLOR_YCBCR_BT2020: + plane_color_ctl |= + PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020; + break; + default: + plane_color_ctl |= + PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601; + } + if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; + } else if (fb->format->is_yuv) { + plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE; + if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; + } + + return plane_color_ctl; +} + +static int +main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) +{ + drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || + (main_plane && main_plane >= fb->format->num_planes / 2)); + + return fb->format->num_planes / 2 + main_plane; +} + +int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) +{ + drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || + ccs_plane < fb->format->num_planes / 2); + + if (is_gen12_ccs_cc_plane(fb, ccs_plane)) + return 0; + + return ccs_plane - fb->format->num_planes / 2; +} + +static int +skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) +{ + struct drm_i915_private *i915 = to_i915(fb->dev); + + if (is_ccs_modifier(fb->modifier)) + return main_to_ccs_plane(fb, main_plane); + else if (INTEL_GEN(i915) < 11 && + intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + return 1; + else + return 0; +} + +static void +skl_program_plane(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + int color_plane) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; + u32 surf_addr = plane_state->color_plane[color_plane].offset; + u32 stride = skl_plane_stride(plane_state, color_plane); + const struct drm_framebuffer *fb = plane_state->hw.fb; + int aux_plane = skl_main_to_aux_plane(fb, color_plane); + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + u32 x = plane_state->color_plane[color_plane].x; + u32 y = plane_state->color_plane[color_plane].y; + u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; + u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; + u8 alpha = plane_state->hw.alpha >> 8; + u32 plane_color_ctl = 0, aux_dist = 0; + unsigned long irqflags; + u32 keymsk, keymax; + u32 plane_ctl = plane_state->ctl; + + plane_ctl |= skl_plane_ctl_crtc(crtc_state); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + plane_color_ctl = plane_state->color_ctl | + glk_plane_color_ctl_crtc(crtc_state); + + /* Sizes are 0 based */ + src_w--; + src_h--; + + keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha); + + keymsk = key->channel_mask & 0x7ffffff; + if (alpha < 0xff) + keymsk |= PLANE_KEYMSK_ALPHA_ENABLE; + + /* The scaler will handle the output position */ + if (plane_state->scaler_id >= 0) { + crtc_x = 0; + crtc_y = 0; + } + + if (aux_plane) { + aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr; + + if (INTEL_GEN(dev_priv) < 12) + aux_dist |= skl_plane_stride(plane_state, aux_plane); + } + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride); + intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id), + (crtc_y << 16) | crtc_x); + intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id), + (src_h << 16) | src_w); + + intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist); + + if (icl_is_hdr_plane(dev_priv, plane_id)) + intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), + plane_state->cus_ctl); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), + plane_color_ctl); + + if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id)) + icl_program_input_csc(plane, crtc_state, plane_state); + + if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC) + intel_uncore_write64_fw(&dev_priv->uncore, + PLANE_CC_VAL(pipe, plane_id), plane_state->ccval); + + skl_write_plane_wm(plane, crtc_state); + + intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), + key->min_value); + intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), keymsk); + intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), keymax); + + intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), + (y << 16) | x); + + if (INTEL_GEN(dev_priv) < 11) + intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), + (plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x); + + if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) + intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); + + /* + * The control register self-arms if the plane was previously + * disabled. Try to make the plane enable atomic by writing + * the control register just before the surface register. + */ + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), + intel_plane_ggtt_offset(plane_state) + surf_addr); + + if (plane_state->scaler_id >= 0) + skl_program_scaler(plane, crtc_state, plane_state); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static void +skl_plane_async_flip(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + bool async_flip) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + unsigned long irqflags; + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + u32 surf_addr = plane_state->color_plane[0].offset; + u32 plane_ctl = plane_state->ctl; + + plane_ctl |= skl_plane_ctl_crtc(crtc_state); + + if (async_flip) + plane_ctl |= PLANE_CTL_ASYNC_FLIP; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), + intel_plane_ggtt_offset(plane_state) + surf_addr); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static void +skl_update_plane(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + int color_plane = 0; + + if (plane_state->planar_linked_plane && !plane_state->planar_slave) + /* Program the UV plane on planar master */ + color_plane = 1; + + skl_program_plane(plane, crtc_state, plane_state, color_plane); +} + +static bool intel_format_is_p01x(u32 format) +{ + switch (format) { + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + return true; + default: + return false; + } +} + +static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + struct drm_format_name_buf format_name; + + if (!fb) + return 0; + + if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) && + is_ccs_modifier(fb->modifier)) { + drm_dbg_kms(&dev_priv->drm, + "RC support only with 0/180 degree rotation (%x)\n", + rotation); + return -EINVAL; + } + + if (rotation & DRM_MODE_REFLECT_X && + fb->modifier == DRM_FORMAT_MOD_LINEAR) { + drm_dbg_kms(&dev_priv->drm, + "horizontal flip is not supported with linear surface formats\n"); + return -EINVAL; + } + + if (drm_rotation_90_or_270(rotation)) { + if (fb->modifier != I915_FORMAT_MOD_Y_TILED && + fb->modifier != I915_FORMAT_MOD_Yf_TILED) { + drm_dbg_kms(&dev_priv->drm, + "Y/Yf tiling required for 90/270!\n"); + return -EINVAL; + } + + /* + * 90/270 is not allowed with RGB64 16:16:16:16 and + * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards. + */ + switch (fb->format->format) { + case DRM_FORMAT_RGB565: + if (INTEL_GEN(dev_priv) >= 11) + break; + fallthrough; + case DRM_FORMAT_C8: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + drm_dbg_kms(&dev_priv->drm, + "Unsupported pixel format %s for 90/270!\n", + drm_get_format_name(fb->format->format, + &format_name)); + return -EINVAL; + default: + break; + } + } + + /* Y-tiling is not supported in IF-ID Interlace mode */ + if (crtc_state->hw.enable && + crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE && + (fb->modifier == I915_FORMAT_MOD_Y_TILED || + fb->modifier == I915_FORMAT_MOD_Yf_TILED || + fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || + fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) { + drm_dbg_kms(&dev_priv->drm, + "Y/Yf tiling not supported in IF-ID mode\n"); + return -EINVAL; + } + + /* Wa_1606054188:tgl,adl-s */ + if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) && + plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE && + intel_format_is_p01x(fb->format->format)) { + drm_dbg_kms(&dev_priv->drm, + "Source color keying not supported with P01x formats\n"); + return -EINVAL; + } + + return 0; +} + +static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); + int crtc_x = plane_state->uapi.dst.x1; + int crtc_w = drm_rect_width(&plane_state->uapi.dst); + int pipe_src_w = crtc_state->pipe_src_w; + + /* + * Display WA #1175: cnl,glk + * Planes other than the cursor may cause FIFO underflow and display + * corruption if starting less than 4 pixels from the right edge of + * the screen. + * Besides the above WA fix the similar problem, where planes other + * than the cursor ending less than 4 pixels from the left edge of the + * screen may cause FIFO underflow and display corruption. + */ + if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && + (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) { + drm_dbg_kms(&dev_priv->drm, + "requested plane X %s position %d invalid (valid range %d-%d)\n", + crtc_x + crtc_w < 4 ? "end" : "start", + crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x, + 4, pipe_src_w - 4); + return -ERANGE; + } + + return 0; +} + +static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; + + /* Display WA #1106 */ + if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && + src_w & 3 && + (rotation == DRM_MODE_ROTATE_270 || + rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) { + DRM_DEBUG_KMS("src width must be multiple of 4 for rotated planar YUV\n"); + return -EINVAL; + } + + return 0; +} + +static int skl_plane_max_scale(struct drm_i915_private *dev_priv, + const struct drm_framebuffer *fb) +{ + /* + * We don't yet know the final source width nor + * whether we can use the HQ scaler mode. Assume + * the best case. + * FIXME need to properly check this later. + */ + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) || + !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + return 0x30000 - 1; + else + return 0x20000 - 1; +} + +static int intel_plane_min_width(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + if (plane->min_width) + return plane->min_width(fb, color_plane, rotation); + else + return 1; +} + +static int intel_plane_max_width(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + if (plane->max_width) + return plane->max_width(fb, color_plane, rotation); + else + return INT_MAX; +} + +static int intel_plane_max_height(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + if (plane->max_height) + return plane->max_height(fb, color_plane, rotation); + else + return INT_MAX; +} + +static bool +skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state, + int main_x, int main_y, u32 main_offset, + int ccs_plane) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + int aux_x = plane_state->color_plane[ccs_plane].x; + int aux_y = plane_state->color_plane[ccs_plane].y; + u32 aux_offset = plane_state->color_plane[ccs_plane].offset; + u32 alignment = intel_surf_alignment(fb, ccs_plane); + int hsub; + int vsub; + + intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); + while (aux_offset >= main_offset && aux_y <= main_y) { + int x, y; + + if (aux_x == main_x && aux_y == main_y) + break; + + if (aux_offset == 0) + break; + + x = aux_x / hsub; + y = aux_y / vsub; + aux_offset = intel_plane_adjust_aligned_offset(&x, &y, + plane_state, + ccs_plane, + aux_offset, + aux_offset - + alignment); + aux_x = x * hsub + aux_x % hsub; + aux_y = y * vsub + aux_y % vsub; + } + + if (aux_x != main_x || aux_y != main_y) + return false; + + plane_state->color_plane[ccs_plane].offset = aux_offset; + plane_state->color_plane[ccs_plane].x = aux_x; + plane_state->color_plane[ccs_plane].y = aux_y; + + return true; +} + + +int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, + int *x, int *y, u32 *offset) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + const int aux_plane = skl_main_to_aux_plane(fb, 0); + const u32 aux_offset = plane_state->color_plane[aux_plane].offset; + const u32 alignment = intel_surf_alignment(fb, 0); + const int w = drm_rect_width(&plane_state->uapi.src) >> 16; + + intel_add_fb_offsets(x, y, plane_state, 0); + *offset = intel_plane_compute_aligned_offset(x, y, plane_state, 0); + if (drm_WARN_ON(&dev_priv->drm, alignment && !is_power_of_2(alignment))) + return -EINVAL; + + /* + * AUX surface offset is specified as the distance from the + * main surface offset, and it must be non-negative. Make + * sure that is what we will get. + */ + if (aux_plane && *offset > aux_offset) + *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, + *offset, + aux_offset & ~(alignment - 1)); + + /* + * When using an X-tiled surface, the plane blows up + * if the x offset + width exceed the stride. + * + * TODO: linear and Y-tiled seem fine, Yf untested, + */ + if (fb->modifier == I915_FORMAT_MOD_X_TILED) { + int cpp = fb->format->cpp[0]; + + while ((*x + w) * cpp > plane_state->color_plane[0].stride) { + if (*offset == 0) { + drm_dbg_kms(&dev_priv->drm, + "Unable to find suitable display surface offset due to X-tiling\n"); + return -EINVAL; + } + + *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, + *offset, + *offset - alignment); + } + } + + return 0; +} + +static int skl_check_main_surface(struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + const unsigned int rotation = plane_state->hw.rotation; + int x = plane_state->uapi.src.x1 >> 16; + int y = plane_state->uapi.src.y1 >> 16; + const int w = drm_rect_width(&plane_state->uapi.src) >> 16; + const int h = drm_rect_height(&plane_state->uapi.src) >> 16; + const int min_width = intel_plane_min_width(plane, fb, 0, rotation); + const int max_width = intel_plane_max_width(plane, fb, 0, rotation); + const int max_height = intel_plane_max_height(plane, fb, 0, rotation); + const int aux_plane = skl_main_to_aux_plane(fb, 0); + const u32 alignment = intel_surf_alignment(fb, 0); + u32 offset; + int ret; + + if (w > max_width || w < min_width || h > max_height) { + drm_dbg_kms(&dev_priv->drm, + "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n", + w, h, min_width, max_width, max_height); + return -EINVAL; + } + + ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset); + if (ret) + return ret; + + /* + * CCS AUX surface doesn't have its own x/y offsets, we must make sure + * they match with the main surface x/y offsets. + */ + if (is_ccs_modifier(fb->modifier)) { + while (!skl_check_main_ccs_coordinates(plane_state, x, y, + offset, aux_plane)) { + if (offset == 0) + break; + + offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, + offset, offset - alignment); + } + + if (x != plane_state->color_plane[aux_plane].x || + y != plane_state->color_plane[aux_plane].y) { + drm_dbg_kms(&dev_priv->drm, + "Unable to find suitable display surface offset due to CCS\n"); + return -EINVAL; + } + } + + drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191); + + plane_state->color_plane[0].offset = offset; + plane_state->color_plane[0].x = x; + plane_state->color_plane[0].y = y; + + /* + * Put the final coordinates back so that the src + * coordinate checks will see the right values. + */ + drm_rect_translate_to(&plane_state->uapi.src, + x << 16, y << 16); + + return 0; +} + +static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *i915 = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + int uv_plane = 1; + int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation); + int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation); + int x = plane_state->uapi.src.x1 >> 17; + int y = plane_state->uapi.src.y1 >> 17; + int w = drm_rect_width(&plane_state->uapi.src) >> 17; + int h = drm_rect_height(&plane_state->uapi.src) >> 17; + u32 offset; + + /* FIXME not quite sure how/if these apply to the chroma plane */ + if (w > max_width || h > max_height) { + drm_dbg_kms(&i915->drm, + "CbCr source size %dx%d too big (limit %dx%d)\n", + w, h, max_width, max_height); + return -EINVAL; + } + + intel_add_fb_offsets(&x, &y, plane_state, uv_plane); + offset = intel_plane_compute_aligned_offset(&x, &y, + plane_state, uv_plane); + + if (is_ccs_modifier(fb->modifier)) { + int ccs_plane = main_to_ccs_plane(fb, uv_plane); + u32 aux_offset = plane_state->color_plane[ccs_plane].offset; + u32 alignment = intel_surf_alignment(fb, uv_plane); + + if (offset > aux_offset) + offset = intel_plane_adjust_aligned_offset(&x, &y, + plane_state, + uv_plane, + offset, + aux_offset & ~(alignment - 1)); + + while (!skl_check_main_ccs_coordinates(plane_state, x, y, + offset, ccs_plane)) { + if (offset == 0) + break; + + offset = intel_plane_adjust_aligned_offset(&x, &y, + plane_state, + uv_plane, + offset, offset - alignment); + } + + if (x != plane_state->color_plane[ccs_plane].x || + y != plane_state->color_plane[ccs_plane].y) { + drm_dbg_kms(&i915->drm, + "Unable to find suitable display surface offset due to CCS\n"); + return -EINVAL; + } + } + + drm_WARN_ON(&i915->drm, x > 8191 || y > 8191); + + plane_state->color_plane[uv_plane].offset = offset; + plane_state->color_plane[uv_plane].x = x; + plane_state->color_plane[uv_plane].y = y; + + return 0; +} + +static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + int src_x = plane_state->uapi.src.x1 >> 16; + int src_y = plane_state->uapi.src.y1 >> 16; + u32 offset; + int ccs_plane; + + for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) { + int main_hsub, main_vsub; + int hsub, vsub; + int x, y; + + if (!is_ccs_plane(fb, ccs_plane) || + is_gen12_ccs_cc_plane(fb, ccs_plane)) + continue; + + intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, + skl_ccs_to_main_plane(fb, ccs_plane)); + intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); + + hsub *= main_hsub; + vsub *= main_vsub; + x = src_x / hsub; + y = src_y / vsub; + + intel_add_fb_offsets(&x, &y, plane_state, ccs_plane); + + offset = intel_plane_compute_aligned_offset(&x, &y, + plane_state, + ccs_plane); + + plane_state->color_plane[ccs_plane].offset = offset; + plane_state->color_plane[ccs_plane].x = (x * hsub + + src_x % hsub) / + main_hsub; + plane_state->color_plane[ccs_plane].y = (y * vsub + + src_y % vsub) / + main_vsub; + } + + return 0; +} + +static int skl_check_plane_surface(struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + int ret, i; + + ret = intel_plane_compute_gtt(plane_state); + if (ret) + return ret; + + if (!plane_state->uapi.visible) + return 0; + + /* + * Handle the AUX surface first since the main surface setup depends on + * it. + */ + if (is_ccs_modifier(fb->modifier)) { + ret = skl_check_ccs_aux_surface(plane_state); + if (ret) + return ret; + } + + if (intel_format_info_is_yuv_semiplanar(fb->format, + fb->modifier)) { + ret = skl_check_nv12_aux_surface(plane_state); + if (ret) + return ret; + } + + for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) { + plane_state->color_plane[i].offset = 0; + plane_state->color_plane[i].x = 0; + plane_state->color_plane[i].y = 0; + } + + ret = skl_check_main_surface(plane_state); + if (ret) + return ret; + + return 0; +} + +static bool intel_fb_scalable(const struct drm_framebuffer *fb) +{ + if (!fb) + return false; + + switch (fb->format->format) { + case DRM_FORMAT_C8: + return false; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + return INTEL_GEN(to_i915(fb->dev)) >= 11; + default: + return true; + } +} + +static int skl_plane_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + int min_scale = DRM_PLANE_HELPER_NO_SCALING; + int max_scale = DRM_PLANE_HELPER_NO_SCALING; + int ret; + + ret = skl_plane_check_fb(crtc_state, plane_state); + if (ret) + return ret; + + /* use scaler when colorkey is not required */ + if (!plane_state->ckey.flags && intel_fb_scalable(fb)) { + min_scale = 1; + max_scale = skl_plane_max_scale(dev_priv, fb); + } + + ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, + min_scale, max_scale, true); + if (ret) + return ret; + + ret = skl_check_plane_surface(plane_state); + if (ret) + return ret; + + if (!plane_state->uapi.visible) + return 0; + + ret = skl_plane_check_dst_coordinates(crtc_state, plane_state); + if (ret) + return ret; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = skl_plane_check_nv12_rotation(plane_state); + if (ret) + return ret; + + /* HW only has 8 bits pixel precision, disable plane if invisible */ + if (!(plane_state->hw.alpha >> 8)) + plane_state->uapi.visible = false; + + plane_state->ctl = skl_plane_ctl(crtc_state, plane_state); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + plane_state->color_ctl = glk_plane_color_ctl(crtc_state, + plane_state); + + if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && + icl_is_hdr_plane(dev_priv, plane->id)) + /* Enable and use MPEG-2 chroma siting */ + plane_state->cus_ctl = PLANE_CUS_ENABLE | + PLANE_CUS_HPHASE_0 | + PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25; + else + plane_state->cus_ctl = 0; + + return 0; +} + +static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + if (!HAS_FBC(dev_priv)) + return false; + + return pipe == PIPE_A && plane_id == PLANE_PRIMARY; +} + +static bool skl_plane_has_planar(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + /* Display WA #0870: skl, bxt */ + if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) + return false; + + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) + return false; + + if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) + return false; + + return true; +} + +static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id, + int *num_formats) +{ + if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { + *num_formats = ARRAY_SIZE(skl_planar_formats); + return skl_planar_formats; + } else { + *num_formats = ARRAY_SIZE(skl_plane_formats); + return skl_plane_formats; + } +} + +static const u32 *glk_get_plane_formats(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id, + int *num_formats) +{ + if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { + *num_formats = ARRAY_SIZE(glk_planar_formats); + return glk_planar_formats; + } else { + *num_formats = ARRAY_SIZE(skl_plane_formats); + return skl_plane_formats; + } +} + +static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id, + int *num_formats) +{ + if (icl_is_hdr_plane(dev_priv, plane_id)) { + *num_formats = ARRAY_SIZE(icl_hdr_plane_formats); + return icl_hdr_plane_formats; + } else if (icl_is_nv12_y_plane(dev_priv, plane_id)) { + *num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats); + return icl_sdr_y_plane_formats; + } else { + *num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats); + return icl_sdr_uv_plane_formats; + } +} + +static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + if (plane_id == PLANE_CURSOR) + return false; + + if (INTEL_GEN(dev_priv) >= 10) + return true; + + if (IS_GEMINILAKE(dev_priv)) + return pipe != PIPE_C; + + return pipe != PIPE_C && + (plane_id == PLANE_PRIMARY || + plane_id == PLANE_SPRITE0); +} + +static bool skl_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) +{ + struct intel_plane *plane = to_intel_plane(_plane); + + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + break; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + if (!plane->has_ccs) + return false; + break; + default: + return false; + } + + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + if (is_ccs_modifier(modifier)) + return true; + fallthrough; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + case DRM_FORMAT_XVYU2101010: + if (modifier == I915_FORMAT_MOD_Yf_TILED) + return true; + fallthrough; + case DRM_FORMAT_C8: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + if (modifier == DRM_FORMAT_MOD_LINEAR || + modifier == I915_FORMAT_MOD_X_TILED || + modifier == I915_FORMAT_MOD_Y_TILED) + return true; + fallthrough; + default: + return false; + } +} + +static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, + enum plane_id plane_id) +{ + /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */ + if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) || + IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0)) + return false; + + return plane_id < PLANE_SPRITE4; +} + +static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) +{ + struct drm_i915_private *dev_priv = to_i915(_plane->dev); + struct intel_plane *plane = to_intel_plane(_plane); + + switch (modifier) { + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id)) + return false; + fallthrough; + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: + break; + default: + return false; + } + + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + if (is_ccs_modifier(modifier)) + return true; + fallthrough; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) + return true; + fallthrough; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_C8: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + if (modifier == DRM_FORMAT_MOD_LINEAR || + modifier == I915_FORMAT_MOD_X_TILED || + modifier == I915_FORMAT_MOD_Y_TILED) + return true; + fallthrough; + default: + return false; + } +} + +static const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv, + enum plane_id plane_id) +{ + if (gen12_plane_supports_mc_ccs(dev_priv, plane_id)) + return gen12_plane_format_modifiers_mc_ccs; + else + return gen12_plane_format_modifiers_rc_ccs; +} + +static const struct drm_plane_funcs skl_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = skl_plane_format_mod_supported, +}; + +static const struct drm_plane_funcs gen12_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = gen12_plane_format_mod_supported, +}; + +static void +skl_plane_enable_flip_done(struct intel_plane *plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + spin_lock_irq(&i915->irq_lock); + bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); + spin_unlock_irq(&i915->irq_lock); +} + +static void +skl_plane_disable_flip_done(struct intel_plane *plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + spin_lock_irq(&i915->irq_lock); + bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); + spin_unlock_irq(&i915->irq_lock); +} + +struct intel_plane * +skl_universal_plane_create(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + const struct drm_plane_funcs *plane_funcs; + struct intel_plane *plane; + enum drm_plane_type plane_type; + unsigned int supported_rotations; + unsigned int supported_csc; + const u64 *modifiers; + const u32 *formats; + int num_formats; + int ret; + + plane = intel_plane_alloc(); + if (IS_ERR(plane)) + return plane; + + plane->pipe = pipe; + plane->id = plane_id; + plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id); + + plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id); + if (plane->has_fbc) { + struct intel_fbc *fbc = &dev_priv->fbc; + + fbc->possible_framebuffer_bits |= plane->frontbuffer_bit; + } + + if (INTEL_GEN(dev_priv) >= 11) { + plane->min_width = icl_plane_min_width; + plane->max_width = icl_plane_max_width; + plane->max_height = icl_plane_max_height; + } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + plane->max_width = glk_plane_max_width; + plane->max_height = skl_plane_max_height; + } else { + plane->max_width = skl_plane_max_width; + plane->max_height = skl_plane_max_height; + } + + plane->max_stride = skl_plane_max_stride; + plane->update_plane = skl_update_plane; + plane->disable_plane = skl_disable_plane; + plane->get_hw_state = skl_plane_get_hw_state; + plane->check_plane = skl_plane_check; + plane->min_cdclk = skl_plane_min_cdclk; + + if (plane_id == PLANE_PRIMARY) { + plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 9, 10); + plane->async_flip = skl_plane_async_flip; + plane->enable_flip_done = skl_plane_enable_flip_done; + plane->disable_flip_done = skl_plane_disable_flip_done; + } + + if (INTEL_GEN(dev_priv) >= 11) + formats = icl_get_plane_formats(dev_priv, pipe, + plane_id, &num_formats); + else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + formats = glk_get_plane_formats(dev_priv, pipe, + plane_id, &num_formats); + else + formats = skl_get_plane_formats(dev_priv, pipe, + plane_id, &num_formats); + + plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id); + if (INTEL_GEN(dev_priv) >= 12) { + modifiers = gen12_get_plane_modifiers(dev_priv, plane_id); + plane_funcs = &gen12_plane_funcs; + } else { + if (plane->has_ccs) + modifiers = skl_plane_format_modifiers_ccs; + else + modifiers = skl_plane_format_modifiers_noccs; + plane_funcs = &skl_plane_funcs; + } + + if (plane_id == PLANE_PRIMARY) + plane_type = DRM_PLANE_TYPE_PRIMARY; + else + plane_type = DRM_PLANE_TYPE_OVERLAY; + + ret = drm_universal_plane_init(&dev_priv->drm, &plane->base, + 0, plane_funcs, + formats, num_formats, modifiers, + plane_type, + "plane %d%c", plane_id + 1, + pipe_name(pipe)); + if (ret) + goto fail; + + supported_rotations = + DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; + + if (INTEL_GEN(dev_priv) >= 10) + supported_rotations |= DRM_MODE_REFLECT_X; + + drm_plane_create_rotation_property(&plane->base, + DRM_MODE_ROTATE_0, + supported_rotations); + + supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020); + + drm_plane_create_color_properties(&plane->base, + supported_csc, + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + + drm_plane_create_alpha_property(&plane->base); + drm_plane_create_blend_mode_property(&plane->base, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); + + drm_plane_create_zpos_immutable_property(&plane->base, plane_id); + + if (INTEL_GEN(dev_priv) >= 12) + drm_plane_enable_fb_damage_clips(&plane->base); + + if (INTEL_GEN(dev_priv) >= 10) + drm_plane_create_scaling_filter_property(&plane->base, + BIT(DRM_SCALING_FILTER_DEFAULT) | + BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); + + drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); + + return plane; + +fail: + intel_plane_free(plane); + + return ERR_PTR(ret); +} + +void +skl_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ + struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + enum plane_id plane_id = plane->id; + enum pipe pipe; + u32 val, base, offset, stride_mult, tiling, alpha; + int fourcc, pixel_format; + unsigned int aligned_height; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + + if (!plane->get_hw_state(plane, &pipe)) + return; + + drm_WARN_ON(dev, pipe != crtc->pipe); + + if (crtc_state->bigjoiner) { + drm_dbg_kms(&dev_priv->drm, + "Unsupported bigjoiner configuration for initial FB\n"); + return; + } + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) { + drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); + return; + } + + fb = &intel_fb->base; + + fb->dev = dev; + + val = intel_de_read(dev_priv, PLANE_CTL(pipe, plane_id)); + + if (INTEL_GEN(dev_priv) >= 11) + pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK; + else + pixel_format = val & PLANE_CTL_FORMAT_MASK; + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + alpha = intel_de_read(dev_priv, + PLANE_COLOR_CTL(pipe, plane_id)); + alpha &= PLANE_COLOR_ALPHA_MASK; + } else { + alpha = val & PLANE_CTL_ALPHA_MASK; + } + + fourcc = skl_format_to_fourcc(pixel_format, + val & PLANE_CTL_ORDER_RGBX, alpha); + fb->format = drm_format_info(fourcc); + + tiling = val & PLANE_CTL_TILED_MASK; + switch (tiling) { + case PLANE_CTL_TILED_LINEAR: + fb->modifier = DRM_FORMAT_MOD_LINEAR; + break; + case PLANE_CTL_TILED_X: + plane_config->tiling = I915_TILING_X; + fb->modifier = I915_FORMAT_MOD_X_TILED; + break; + case PLANE_CTL_TILED_Y: + plane_config->tiling = I915_TILING_Y; + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) + fb->modifier = INTEL_GEN(dev_priv) >= 12 ? + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS : + I915_FORMAT_MOD_Y_TILED_CCS; + else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; + else + fb->modifier = I915_FORMAT_MOD_Y_TILED; + break; + case PLANE_CTL_TILED_YF: + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; + else + fb->modifier = I915_FORMAT_MOD_Yf_TILED; + break; + default: + MISSING_CASE(tiling); + goto error; + } + + /* + * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr + * while i915 HW rotation is clockwise, thats why this swapping. + */ + switch (val & PLANE_CTL_ROTATE_MASK) { + case PLANE_CTL_ROTATE_0: + plane_config->rotation = DRM_MODE_ROTATE_0; + break; + case PLANE_CTL_ROTATE_90: + plane_config->rotation = DRM_MODE_ROTATE_270; + break; + case PLANE_CTL_ROTATE_180: + plane_config->rotation = DRM_MODE_ROTATE_180; + break; + case PLANE_CTL_ROTATE_270: + plane_config->rotation = DRM_MODE_ROTATE_90; + break; + } + + if (INTEL_GEN(dev_priv) >= 10 && + val & PLANE_CTL_FLIP_HORIZONTAL) + plane_config->rotation |= DRM_MODE_REFLECT_X; + + /* 90/270 degree rotation would require extra work */ + if (drm_rotation_90_or_270(plane_config->rotation)) + goto error; + + base = intel_de_read(dev_priv, PLANE_SURF(pipe, plane_id)) & 0xfffff000; + plane_config->base = base; + + offset = intel_de_read(dev_priv, PLANE_OFFSET(pipe, plane_id)); + + val = intel_de_read(dev_priv, PLANE_SIZE(pipe, plane_id)); + fb->height = ((val >> 16) & 0xffff) + 1; + fb->width = ((val >> 0) & 0xffff) + 1; + + val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id)); + stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0); + fb->pitches[0] = (val & 0x3ff) * stride_mult; + + aligned_height = intel_fb_align_height(fb, 0, fb->height); + + plane_config->size = fb->pitches[0] * aligned_height; + + drm_dbg_kms(&dev_priv->drm, + "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + crtc->base.name, plane->base.name, fb->width, fb->height, + fb->format->cpp[0] * 8, base, fb->pitches[0], + plane_config->size); + + plane_config->fb = intel_fb; + return; + +error: + kfree(intel_fb); +} + diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h new file mode 100644 index 000000000000..70eb5010cd28 --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ + +#ifndef _SKL_UNIVERSAL_PLANE_H_ +#define _SKL_UNIVERSAL_PLANE_H_ + +#include + +struct drm_framebuffer; +struct drm_i915_private; +struct intel_crtc; +struct intel_initial_plane_config; +struct intel_plane_state; + +enum pipe; +enum plane_id; + +struct intel_plane * +skl_universal_plane_create(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id); + +void skl_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config); + +int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); + +int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane); +int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, + int *x, int *y, u32 *offset); + +#endif diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c58e5077590d..8c42fa51c0f6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -38,6 +38,7 @@ #include "display/intel_display_types.h" #include "display/intel_fbc.h" #include "display/intel_sprite.h" +#include "display/skl_universal_plane.h" #include "gt/intel_llc.h" From patchwork Thu Feb 4 19:43:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068543 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3307CC433E0 for ; Thu, 4 Feb 2021 19:44:14 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CFF3B64F45 for ; Thu, 4 Feb 2021 19:44:13 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CFF3B64F45 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4FA206EE4C; Thu, 4 Feb 2021 19:44:13 +0000 (UTC) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id EA4976EE4C for ; Thu, 4 Feb 2021 19:44:11 +0000 (UTC) IronPort-SDR: aKRd0zluK8UIOp+TIvNdpESxMxvHy7iEPZ6PqEgSYiOZb9XC7T6PCXCE9GsYlL14EnaseOgG9a ZMvE5il97SJw== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="177812328" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="177812328" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:10 -0800 IronPort-SDR: 2W6+gm3U5T8K2GqbqdeD769h3Bnp9cCuoPOmr7bG5ZV7YQqA8wmK+C18ECCxX9O/bFldkKVWCU ul9vZQEWfydQ== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="373106998" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:03 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:21 +0200 Message-Id: <8a037408fcdb31d6bb07c073c5e6b3290218e6e8.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 04/10] drm/i915: move pipe update code into crtc. (v2) 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie Daniel suggested this should move here. v2: move vrr code. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/display/intel_crtc.c | 245 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_sprite.c | 242 ------------------- 2 files changed, 245 insertions(+), 242 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index eb478712c381..fdc896c55179 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -10,6 +10,9 @@ #include #include +#include "i915_trace.h" +#include "i915_vgpu.h" + #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_color.h" @@ -17,8 +20,11 @@ #include "intel_cursor.h" #include "intel_display_debugfs.h" #include "intel_display_types.h" +#include "intel_dsi.h" #include "intel_pipe_crc.h" +#include "intel_psr.h" #include "intel_sprite.h" +#include "intel_vrr.h" #include "i9xx_plane.h" #include "skl_universal_plane.h" @@ -332,3 +338,242 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) return ret; } + +int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, + int usecs) +{ + /* paranoia */ + if (!adjusted_mode->crtc_htotal) + return 1; + + return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, + 1000 * adjusted_mode->crtc_htotal); +} + +static int intel_mode_vblank_start(const struct drm_display_mode *mode) +{ + int vblank_start = mode->crtc_vblank_start; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + + return vblank_start; +} + +/** + * intel_pipe_update_start() - start update of a set of display registers + * @new_crtc_state: the new crtc state + * + * Mark the start of an update to pipe registers that should be updated + * atomically regarding vblank. If the next vblank will happens within + * the next 100 us, this function waits until the vblank passes. + * + * After a successful call to this function, interrupts will be disabled + * until a subsequent call to intel_pipe_update_end(). That is done to + * avoid random delays. + */ +void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; + long timeout = msecs_to_jiffies_timeout(1); + int scanline, min, max, vblank_start; + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); + bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); + DEFINE_WAIT(wait); + u32 psr_status; + + if (new_crtc_state->uapi.async_flip) + return; + + if (new_crtc_state->vrr.enable) + vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); + else + vblank_start = intel_mode_vblank_start(adjusted_mode); + + /* FIXME needs to be calibrated sensibly */ + min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, + VBLANK_EVASION_TIME_US); + max = vblank_start - 1; + + if (min <= 0 || max <= 0) + goto irq_disable; + + if (drm_WARN_ON(&dev_priv->drm, drm_crtc_vblank_get(&crtc->base))) + goto irq_disable; + + /* + * Wait for psr to idle out after enabling the VBL interrupts + * VBL interrupts will start the PSR exit and prevent a PSR + * re-entry as well. + */ + if (intel_psr_wait_for_idle(new_crtc_state, &psr_status)) + drm_err(&dev_priv->drm, + "PSR idle timed out 0x%x, atomic update may fail\n", + psr_status); + + local_irq_disable(); + + crtc->debug.min_vbl = min; + crtc->debug.max_vbl = max; + trace_intel_pipe_update_start(crtc); + + for (;;) { + /* + * prepare_to_wait() has a memory barrier, which guarantees + * other CPUs can see the task state update by the time we + * read the scanline. + */ + prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); + + scanline = intel_get_crtc_scanline(crtc); + if (scanline < min || scanline > max) + break; + + if (!timeout) { + drm_err(&dev_priv->drm, + "Potential atomic update failure on pipe %c\n", + pipe_name(crtc->pipe)); + break; + } + + local_irq_enable(); + + timeout = schedule_timeout(timeout); + + local_irq_disable(); + } + + finish_wait(wq, &wait); + + drm_crtc_vblank_put(&crtc->base); + + /* + * On VLV/CHV DSI the scanline counter would appear to + * increment approx. 1/3 of a scanline before start of vblank. + * The registers still get latched at start of vblank however. + * This means we must not write any registers on the first + * line of vblank (since not the whole line is actually in + * vblank). And unfortunately we can't use the interrupt to + * wait here since it will fire too soon. We could use the + * frame start interrupt instead since it will fire after the + * critical scanline, but that would require more changes + * in the interrupt code. So for now we'll just do the nasty + * thing and poll for the bad scanline to pass us by. + * + * FIXME figure out if BXT+ DSI suffers from this as well + */ + while (need_vlv_dsi_wa && scanline == vblank_start) + scanline = intel_get_crtc_scanline(crtc); + + crtc->debug.scanline_start = scanline; + crtc->debug.start_vbl_time = ktime_get(); + crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); + + trace_intel_pipe_update_vblank_evaded(crtc); + return; + +irq_disable: + local_irq_disable(); +} + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) +static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) +{ + u64 delta = ktime_to_ns(ktime_sub(end, crtc->debug.start_vbl_time)); + unsigned int h; + + h = ilog2(delta >> 9); + if (h >= ARRAY_SIZE(crtc->debug.vbl.times)) + h = ARRAY_SIZE(crtc->debug.vbl.times) - 1; + crtc->debug.vbl.times[h]++; + + crtc->debug.vbl.sum += delta; + if (!crtc->debug.vbl.min || delta < crtc->debug.vbl.min) + crtc->debug.vbl.min = delta; + if (delta > crtc->debug.vbl.max) + crtc->debug.vbl.max = delta; + + if (delta > 1000 * VBLANK_EVASION_TIME_US) { + drm_dbg_kms(crtc->base.dev, + "Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n", + pipe_name(crtc->pipe), + div_u64(delta, 1000), + VBLANK_EVASION_TIME_US); + crtc->debug.vbl.over++; + } +} +#else +static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} +#endif + +/** + * intel_pipe_update_end() - end update of a set of display registers + * @new_crtc_state: the new crtc state + * + * Mark the end of an update started with intel_pipe_update_start(). This + * re-enables interrupts and verifies the update was actually completed + * before a vblank. + */ +void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + enum pipe pipe = crtc->pipe; + int scanline_end = intel_get_crtc_scanline(crtc); + u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); + ktime_t end_vbl_time = ktime_get(); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + if (new_crtc_state->uapi.async_flip) + return; + + trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); + + /* + * Incase of mipi dsi command mode, we need to set frame update + * request for every commit. + */ + if (INTEL_GEN(dev_priv) >= 11 && + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI)) + icl_dsi_frame_update(new_crtc_state); + + /* We're still in the vblank-evade critical section, this can't race. + * Would be slightly nice to just grab the vblank count and arm the + * event outside of the critical section - the spinlock might spin for a + * while ... */ + if (new_crtc_state->uapi.event) { + drm_WARN_ON(&dev_priv->drm, + drm_crtc_vblank_get(&crtc->base) != 0); + + spin_lock(&crtc->base.dev->event_lock); + drm_crtc_arm_vblank_event(&crtc->base, + new_crtc_state->uapi.event); + spin_unlock(&crtc->base.dev->event_lock); + + new_crtc_state->uapi.event = NULL; + } + + local_irq_enable(); + + /* Send VRR Push to terminate Vblank */ + intel_vrr_send_push(new_crtc_state); + + if (intel_vgpu_active(dev_priv)) + return; + + if (crtc->debug.start_vbl_count && + crtc->debug.start_vbl_count != end_vbl_count) { + drm_err(&dev_priv->drm, + "Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", + pipe_name(pipe), crtc->debug.start_vbl_count, + end_vbl_count, + ktime_us_delta(end_vbl_time, + crtc->debug.start_vbl_time), + crtc->debug.min_vbl, crtc->debug.max_vbl, + crtc->debug.scanline_start, scanline_end); + } + + dbg_vblank_evade(crtc, end_vbl_time); +} diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index a5b05ec2f232..b8288330dbc9 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -45,252 +45,10 @@ #include "intel_atomic_plane.h" #include "intel_display_types.h" #include "intel_frontbuffer.h" -#include "intel_pm.h" -#include "intel_psr.h" -#include "intel_dsi.h" #include "intel_sprite.h" #include "i9xx_plane.h" #include "intel_vrr.h" -int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, - int usecs) -{ - /* paranoia */ - if (!adjusted_mode->crtc_htotal) - return 1; - - return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, - 1000 * adjusted_mode->crtc_htotal); -} - -static int intel_mode_vblank_start(const struct drm_display_mode *mode) -{ - int vblank_start = mode->crtc_vblank_start; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - vblank_start = DIV_ROUND_UP(vblank_start, 2); - - return vblank_start; -} - -/** - * intel_pipe_update_start() - start update of a set of display registers - * @new_crtc_state: the new crtc state - * - * Mark the start of an update to pipe registers that should be updated - * atomically regarding vblank. If the next vblank will happens within - * the next 100 us, this function waits until the vblank passes. - * - * After a successful call to this function, interrupts will be disabled - * until a subsequent call to intel_pipe_update_end(). That is done to - * avoid random delays. - */ -void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; - long timeout = msecs_to_jiffies_timeout(1); - int scanline, min, max, vblank_start; - wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); - bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); - DEFINE_WAIT(wait); - u32 psr_status; - - if (new_crtc_state->uapi.async_flip) - return; - - if (new_crtc_state->vrr.enable) - vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); - else - vblank_start = intel_mode_vblank_start(adjusted_mode); - - /* FIXME needs to be calibrated sensibly */ - min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, - VBLANK_EVASION_TIME_US); - max = vblank_start - 1; - - if (min <= 0 || max <= 0) - goto irq_disable; - - if (drm_WARN_ON(&dev_priv->drm, drm_crtc_vblank_get(&crtc->base))) - goto irq_disable; - - /* - * Wait for psr to idle out after enabling the VBL interrupts - * VBL interrupts will start the PSR exit and prevent a PSR - * re-entry as well. - */ - if (intel_psr_wait_for_idle(new_crtc_state, &psr_status)) - drm_err(&dev_priv->drm, - "PSR idle timed out 0x%x, atomic update may fail\n", - psr_status); - - local_irq_disable(); - - crtc->debug.min_vbl = min; - crtc->debug.max_vbl = max; - trace_intel_pipe_update_start(crtc); - - for (;;) { - /* - * prepare_to_wait() has a memory barrier, which guarantees - * other CPUs can see the task state update by the time we - * read the scanline. - */ - prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); - - scanline = intel_get_crtc_scanline(crtc); - if (scanline < min || scanline > max) - break; - - if (!timeout) { - drm_err(&dev_priv->drm, - "Potential atomic update failure on pipe %c\n", - pipe_name(crtc->pipe)); - break; - } - - local_irq_enable(); - - timeout = schedule_timeout(timeout); - - local_irq_disable(); - } - - finish_wait(wq, &wait); - - drm_crtc_vblank_put(&crtc->base); - - /* - * On VLV/CHV DSI the scanline counter would appear to - * increment approx. 1/3 of a scanline before start of vblank. - * The registers still get latched at start of vblank however. - * This means we must not write any registers on the first - * line of vblank (since not the whole line is actually in - * vblank). And unfortunately we can't use the interrupt to - * wait here since it will fire too soon. We could use the - * frame start interrupt instead since it will fire after the - * critical scanline, but that would require more changes - * in the interrupt code. So for now we'll just do the nasty - * thing and poll for the bad scanline to pass us by. - * - * FIXME figure out if BXT+ DSI suffers from this as well - */ - while (need_vlv_dsi_wa && scanline == vblank_start) - scanline = intel_get_crtc_scanline(crtc); - - crtc->debug.scanline_start = scanline; - crtc->debug.start_vbl_time = ktime_get(); - crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); - - trace_intel_pipe_update_vblank_evaded(crtc); - return; - -irq_disable: - local_irq_disable(); -} - -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) -static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) -{ - u64 delta = ktime_to_ns(ktime_sub(end, crtc->debug.start_vbl_time)); - unsigned int h; - - h = ilog2(delta >> 9); - if (h >= ARRAY_SIZE(crtc->debug.vbl.times)) - h = ARRAY_SIZE(crtc->debug.vbl.times) - 1; - crtc->debug.vbl.times[h]++; - - crtc->debug.vbl.sum += delta; - if (!crtc->debug.vbl.min || delta < crtc->debug.vbl.min) - crtc->debug.vbl.min = delta; - if (delta > crtc->debug.vbl.max) - crtc->debug.vbl.max = delta; - - if (delta > 1000 * VBLANK_EVASION_TIME_US) { - drm_dbg_kms(crtc->base.dev, - "Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n", - pipe_name(crtc->pipe), - div_u64(delta, 1000), - VBLANK_EVASION_TIME_US); - crtc->debug.vbl.over++; - } -} -#else -static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} -#endif - -/** - * intel_pipe_update_end() - end update of a set of display registers - * @new_crtc_state: the new crtc state - * - * Mark the end of an update started with intel_pipe_update_start(). This - * re-enables interrupts and verifies the update was actually completed - * before a vblank. - */ -void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - enum pipe pipe = crtc->pipe; - int scanline_end = intel_get_crtc_scanline(crtc); - u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); - ktime_t end_vbl_time = ktime_get(); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - - if (new_crtc_state->uapi.async_flip) - return; - - trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); - - /* - * Incase of mipi dsi command mode, we need to set frame update - * request for every commit. - */ - if (INTEL_GEN(dev_priv) >= 11 && - intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI)) - icl_dsi_frame_update(new_crtc_state); - - /* We're still in the vblank-evade critical section, this can't race. - * Would be slightly nice to just grab the vblank count and arm the - * event outside of the critical section - the spinlock might spin for a - * while ... */ - if (new_crtc_state->uapi.event) { - drm_WARN_ON(&dev_priv->drm, - drm_crtc_vblank_get(&crtc->base) != 0); - - spin_lock(&crtc->base.dev->event_lock); - drm_crtc_arm_vblank_event(&crtc->base, - new_crtc_state->uapi.event); - spin_unlock(&crtc->base.dev->event_lock); - - new_crtc_state->uapi.event = NULL; - } - - local_irq_enable(); - - /* Send VRR Push to terminate Vblank */ - intel_vrr_send_push(new_crtc_state); - - if (intel_vgpu_active(dev_priv)) - return; - - if (crtc->debug.start_vbl_count && - crtc->debug.start_vbl_count != end_vbl_count) { - drm_err(&dev_priv->drm, - "Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", - pipe_name(pipe), crtc->debug.start_vbl_count, - end_vbl_count, - ktime_us_delta(end_vbl_time, - crtc->debug.start_vbl_time), - crtc->debug.min_vbl, crtc->debug.max_vbl, - crtc->debug.scanline_start, scanline_end); - } - - dbg_vblank_evade(crtc, end_vbl_time); -} - int intel_plane_check_stride(const struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); From patchwork Thu Feb 4 19:43:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068545 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1DF93C433E0 for ; Thu, 4 Feb 2021 19:44:19 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BF49464F6D for ; Thu, 4 Feb 2021 19:44:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BF49464F6D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3EBD76EE48; Thu, 4 Feb 2021 19:44:18 +0000 (UTC) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4B3636EE48 for ; Thu, 4 Feb 2021 19:44:17 +0000 (UTC) IronPort-SDR: Of+lFD9p98MP5GtVD2qbMqYPr3GtS3/vveKZx5Rkbdy96H600LQqjDf2mSgL96wSKtTw9T7Wcs cOH6vd+qelUA== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="181384264" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="181384264" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:16 -0800 IronPort-SDR: KarPNlDA1YLcVnFhJIBIehqmUMyprSxOeqextSRCTg1XuA+WXVj7XUMUkKgaa6MjtuQz1nAEGe 2jkY1q2/2QBA== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="415489208" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:13 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:22 +0200 Message-Id: <6a350d348f1cb7dadce46ee1e0f6c5c45753c571.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 05/10] drm/i915: split fb scalable checks into g4x and skl versions 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie This just cleans these up a bit. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/display/intel_sprite.c | 7 +++---- drivers/gpu/drm/i915/display/skl_universal_plane.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index b8288330dbc9..46fcb5b9983f 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -1365,19 +1365,18 @@ g4x_plane_get_hw_state(struct intel_plane *plane, return ret; } -static bool intel_fb_scalable(const struct drm_framebuffer *fb) +static bool g4x_fb_scalable(const struct drm_framebuffer *fb) { if (!fb) return false; switch (fb->format->format) { case DRM_FORMAT_C8: - return false; case DRM_FORMAT_XRGB16161616F: case DRM_FORMAT_ARGB16161616F: case DRM_FORMAT_XBGR16161616F: case DRM_FORMAT_ABGR16161616F: - return INTEL_GEN(to_i915(fb->dev)) >= 11; + return false; default: return true; } @@ -1454,7 +1453,7 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state, int max_scale = DRM_PLANE_HELPER_NO_SCALING; int ret; - if (intel_fb_scalable(plane_state->hw.fb)) { + if (g4x_fb_scalable(plane_state->hw.fb)) { if (INTEL_GEN(dev_priv) < 7) { min_scale = 1; max_scale = 16 << 16; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 29c2e3693e8b..4ae1a2ef29ec 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1618,7 +1618,7 @@ static int skl_check_plane_surface(struct intel_plane_state *plane_state) return 0; } -static bool intel_fb_scalable(const struct drm_framebuffer *fb) +static bool skl_fb_scalable(const struct drm_framebuffer *fb) { if (!fb) return false; @@ -1651,7 +1651,7 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, return ret; /* use scaler when colorkey is not required */ - if (!plane_state->ckey.flags && intel_fb_scalable(fb)) { + if (!plane_state->ckey.flags && skl_fb_scalable(fb)) { min_scale = 1; max_scale = skl_plane_max_scale(dev_priv, fb); } From patchwork Thu Feb 4 19:43:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068549 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 42983C433E9 for ; Thu, 4 Feb 2021 19:44:34 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EC9C064F6D for ; Thu, 4 Feb 2021 19:44:33 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EC9C064F6D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 595196EE51; Thu, 4 Feb 2021 19:44:33 +0000 (UTC) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5720E6EE4F for ; Thu, 4 Feb 2021 19:44:31 +0000 (UTC) IronPort-SDR: 8lHkRJ+mY4dz5ebp/9cHIFvkS+gGQyA+gSwUrNg8rC71Zp7iHH9gE3ECLG8+Nh7iKrd9yz6odI SXCsYZ3oF3Sg== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="160477190" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="160477190" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:23 -0800 IronPort-SDR: Odw3JYQIyIbA/lr2za0gHpny1tVIxe2QrBg9jPCYLwwiFycQNBkhxZQqf2AlZEiSPQXz35wJTI tcKyyD+HVV1w== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="357318731" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:20 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:23 +0200 Message-Id: <5f5ff960eebdd83b0585fd7072be9468b7ff587f.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 06/10] drm/i915: move is_ccs_modifier to an inline 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie There is no need for this to be out of line. Reviewed-by: Ville Syrjälä Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 9 --------- drivers/gpu/drm/i915/display/intel_display.h | 1 - drivers/gpu/drm/i915/display/intel_display_types.h | 9 +++++++++ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8211cb40b5c6..3758627f0f7d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1823,15 +1823,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd) } } -bool is_ccs_modifier(u64 modifier) -{ - return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS; -} - static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane) { return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)], diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 251398128349..c176c31c3ec2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -508,7 +508,6 @@ void intel_link_compute_m_n(u16 bpp, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n, bool constant_n, bool fec_enable); -bool is_ccs_modifier(u64 modifier); void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv); u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, u32 pixel_format, u64 modifier); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 23a74496c172..9222e4f9348f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1895,6 +1895,15 @@ static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv, return dev_priv->fdi_pll_freq; } +static inline bool is_ccs_modifier(u64 modifier) +{ + return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_CCS || + modifier == I915_FORMAT_MOD_Yf_TILED_CCS; +} + static inline bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) { if (!is_ccs_modifier(fb->modifier)) From patchwork Thu Feb 4 19:43:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068547 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D4EDAC433DB for ; Thu, 4 Feb 2021 19:44:32 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 859D160235 for ; Thu, 4 Feb 2021 19:44:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 859D160235 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 15BF66EE4F; Thu, 4 Feb 2021 19:44:32 +0000 (UTC) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2BD556EE4F for ; Thu, 4 Feb 2021 19:44:30 +0000 (UTC) IronPort-SDR: xyFF+e+qHt18QOa/cpxRL3NPdjUFwkIIdifsFcVW+cUGYLb7E/NtvFa1knr4EemQeJu3aezcX4 94W0OVzi88wA== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="177812369" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="177812369" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:29 -0800 IronPort-SDR: /w2JwirOfJMaWZlhUVsjgA8zdv1B3SzEiUPv/nZ5ZhovbaQGbSWhs0OaH9DrB3i3scUYM06cO+ OOfGDmQn0kQw== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="508253588" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:26 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:24 +0200 Message-Id: <7524f18c2c37b933fd328e4e7fab5d6bd192f381.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 07/10] drm/i915: migrate pll enable/disable code to intel_dpll.[ch] 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie This moves the older i9xx/vlv/chv enable/disable to dpll file. Signed-off-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 512 ------------------- drivers/gpu/drm/i915/display/intel_display.h | 3 - drivers/gpu/drm/i915/display/intel_dp.c | 1 + drivers/gpu/drm/i915/display/intel_dpll.c | 509 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dpll.h | 18 + drivers/gpu/drm/i915/display/intel_pps.c | 1 + 6 files changed, 529 insertions(+), 515 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3758627f0f7d..009f38cbd3c5 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -113,10 +113,6 @@ static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state); static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state); static void hsw_set_pipeconf(const struct intel_crtc_state *crtc_state); static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state); -static void vlv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config); -static void chv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config); static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); @@ -569,224 +565,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, assert_pch_hdmi_disabled(dev_priv, pipe, PORT_D, PCH_HDMID); } -static void _vlv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); - intel_de_posting_read(dev_priv, DPLL(pipe)); - udelay(150); - - if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) - drm_err(&dev_priv->drm, "DPLL %d failed to lock\n", pipe); -} - -static void vlv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); - - /* PLL is protected by panel, make sure we can write it */ - assert_panel_unlocked(dev_priv, pipe); - - if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) - _vlv_enable_pll(crtc, pipe_config); - - intel_de_write(dev_priv, DPLL_MD(pipe), - pipe_config->dpll_hw_state.dpll_md); - intel_de_posting_read(dev_priv, DPLL_MD(pipe)); -} - - -static void _chv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); - u32 tmp; - - vlv_dpio_get(dev_priv); - - /* Enable back the 10bit clock to display controller */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); - tmp |= DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); - - vlv_dpio_put(dev_priv); - - /* - * Need to wait > 100ns between dclkp clock enable bit and PLL enable. - */ - udelay(1); - - /* Enable PLL */ - intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); - - /* Check PLL is locked */ - if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) - drm_err(&dev_priv->drm, "PLL %d failed to lock\n", pipe); -} - -static void chv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); - - /* PLL is protected by panel, make sure we can write it */ - assert_panel_unlocked(dev_priv, pipe); - - if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) - _chv_enable_pll(crtc, pipe_config); - - if (pipe != PIPE_A) { - /* - * WaPixelRepeatModeFixForC0:chv - * - * DPLLCMD is AWOL. Use chicken bits to propagate - * the value from DPLLBMD to either pipe B or C. - */ - intel_de_write(dev_priv, CBR4_VLV, CBR_DPLLBMD_PIPE(pipe)); - intel_de_write(dev_priv, DPLL_MD(PIPE_B), - pipe_config->dpll_hw_state.dpll_md); - intel_de_write(dev_priv, CBR4_VLV, 0); - dev_priv->chv_dpll_md[pipe] = pipe_config->dpll_hw_state.dpll_md; - - /* - * DPLLB VGA mode also seems to cause problems. - * We should always have it disabled. - */ - drm_WARN_ON(&dev_priv->drm, - (intel_de_read(dev_priv, DPLL(PIPE_B)) & - DPLL_VGA_MODE_DIS) == 0); - } else { - intel_de_write(dev_priv, DPLL_MD(pipe), - pipe_config->dpll_hw_state.dpll_md); - intel_de_posting_read(dev_priv, DPLL_MD(pipe)); - } -} - -static bool i9xx_has_pps(struct drm_i915_private *dev_priv) -{ - if (IS_I830(dev_priv)) - return false; - - return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv); -} - -static void i9xx_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - i915_reg_t reg = DPLL(crtc->pipe); - u32 dpll = crtc_state->dpll_hw_state.dpll; - int i; - - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); - - /* PLL is protected by panel, make sure we can write it */ - if (i9xx_has_pps(dev_priv)) - assert_panel_unlocked(dev_priv, crtc->pipe); - - /* - * Apparently we need to have VGA mode enabled prior to changing - * the P1/P2 dividers. Otherwise the DPLL will keep using the old - * dividers, even though the register value does change. - */ - intel_de_write(dev_priv, reg, dpll & ~DPLL_VGA_MODE_DIS); - intel_de_write(dev_priv, reg, dpll); - - /* Wait for the clocks to stabilize. */ - intel_de_posting_read(dev_priv, reg); - udelay(150); - - if (INTEL_GEN(dev_priv) >= 4) { - intel_de_write(dev_priv, DPLL_MD(crtc->pipe), - crtc_state->dpll_hw_state.dpll_md); - } else { - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - intel_de_write(dev_priv, reg, dpll); - } - - /* We do this three times for luck */ - for (i = 0; i < 3; i++) { - intel_de_write(dev_priv, reg, dpll); - intel_de_posting_read(dev_priv, reg); - udelay(150); /* wait for warmup */ - } -} - -static void i9xx_disable_pll(const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - /* Don't disable pipe or pipe PLLs if needed */ - if (IS_I830(dev_priv)) - return; - - /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); - - intel_de_write(dev_priv, DPLL(pipe), DPLL_VGA_MODE_DIS); - intel_de_posting_read(dev_priv, DPLL(pipe)); -} - -static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - u32 val; - - /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, (enum transcoder)pipe); - - val = DPLL_INTEGRATED_REF_CLK_VLV | - DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; - if (pipe != PIPE_A) - val |= DPLL_INTEGRATED_CRI_CLK_VLV; - - intel_de_write(dev_priv, DPLL(pipe), val); - intel_de_posting_read(dev_priv, DPLL(pipe)); -} - -static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - enum dpio_channel port = vlv_pipe_to_channel(pipe); - u32 val; - - /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, (enum transcoder)pipe); - - val = DPLL_SSC_REF_CLK_CHV | - DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; - if (pipe != PIPE_A) - val |= DPLL_INTEGRATED_CRI_CLK_VLV; - - intel_de_write(dev_priv, DPLL(pipe), val); - intel_de_posting_read(dev_priv, DPLL(pipe)); - - vlv_dpio_get(dev_priv); - - /* Disable 10bit clock to display controller */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); - val &= ~DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); - - vlv_dpio_put(dev_priv); -} - void vlv_wait_port_ready(struct drm_i915_private *dev_priv, struct intel_digital_port *dig_port, unsigned int expected_mask) @@ -5771,35 +5549,6 @@ static void intel_panel_sanitize_ssc(struct drm_i915_private *dev_priv) } } -static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe - pipe) -{ - u32 reg_val; - - /* - * PLLB opamp always calibrates to max value of 0x3f, force enable it - * and set it to a reasonable value instead. - */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); - reg_val &= 0xffffff00; - reg_val |= 0x00000030; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); - reg_val &= 0x00ffffff; - reg_val |= 0x8c000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); - - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); - reg_val &= 0xffffff00; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); - reg_val &= 0x00ffffff; - reg_val |= 0xb0000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); -} - static void intel_pch_transcoder_set_m_n(const struct intel_crtc_state *crtc_state, const struct intel_link_m_n *m_n) { @@ -5895,267 +5644,6 @@ void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_s intel_cpu_transcoder_set_m_n(crtc_state, dp_m_n, dp_m2_n2); } -static void vlv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - u32 mdiv; - u32 bestn, bestm1, bestm2, bestp1, bestp2; - u32 coreclk, reg_val; - - /* Enable Refclk */ - intel_de_write(dev_priv, DPLL(pipe), - pipe_config->dpll_hw_state.dpll & ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV)); - - /* No need to actually set up the DPLL with DSI */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - vlv_dpio_get(dev_priv); - - bestn = pipe_config->dpll.n; - bestm1 = pipe_config->dpll.m1; - bestm2 = pipe_config->dpll.m2; - bestp1 = pipe_config->dpll.p1; - bestp2 = pipe_config->dpll.p2; - - /* See eDP HDMI DPIO driver vbios notes doc */ - - /* PLL B needs special handling */ - if (pipe == PIPE_B) - vlv_pllb_recal_opamp(dev_priv, pipe); - - /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); - - /* Disable target IRef on PLL */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); - reg_val &= 0x00ffffff; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); - - /* Disable fast lock */ - vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); - - /* Set idtafcrecal before PLL is enabled */ - mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); - mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); - mdiv |= ((bestn << DPIO_N_SHIFT)); - mdiv |= (1 << DPIO_K_SHIFT); - - /* - * Post divider depends on pixel clock rate, DAC vs digital (and LVDS, - * but we don't support that). - * Note: don't use the DAC post divider as it seems unstable. - */ - mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); - - mdiv |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); - - /* Set HBR and RBR LPF coefficients */ - if (pipe_config->port_clock == 162000 || - intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) || - intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), - 0x009f0003); - else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), - 0x00d0000f); - - if (intel_crtc_has_dp_encoder(pipe_config)) { - /* Use SSC source */ - if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df40000); - else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df70000); - } else { /* HDMI or VGA */ - /* Use bend source */ - if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df70000); - else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df40000); - } - - coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); - coreclk = (coreclk & 0x0000ff00) | 0x01c00000; - if (intel_crtc_has_dp_encoder(pipe_config)) - coreclk |= 0x01000000; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); - - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); - - vlv_dpio_put(dev_priv); -} - -static void chv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); - u32 loopfilter, tribuf_calcntr; - u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; - u32 dpio_val; - int vco; - - /* Enable Refclk and SSC */ - intel_de_write(dev_priv, DPLL(pipe), - pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE); - - /* No need to actually set up the DPLL with DSI */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - bestn = pipe_config->dpll.n; - bestm2_frac = pipe_config->dpll.m2 & 0x3fffff; - bestm1 = pipe_config->dpll.m1; - bestm2 = pipe_config->dpll.m2 >> 22; - bestp1 = pipe_config->dpll.p1; - bestp2 = pipe_config->dpll.p2; - vco = pipe_config->dpll.vco; - dpio_val = 0; - loopfilter = 0; - - vlv_dpio_get(dev_priv); - - /* p1 and p2 divider */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port), - 5 << DPIO_CHV_S1_DIV_SHIFT | - bestp1 << DPIO_CHV_P1_DIV_SHIFT | - bestp2 << DPIO_CHV_P2_DIV_SHIFT | - 1 << DPIO_CHV_K_DIV_SHIFT); - - /* Feedback post-divider - m2 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2); - - /* Feedback refclk divider - n and m1 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port), - DPIO_CHV_M1_DIV_BY_2 | - 1 << DPIO_CHV_N_DIV_SHIFT); - - /* M2 fraction division */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac); - - /* M2 fraction division enable */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); - dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); - dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT); - if (bestm2_frac) - dpio_val |= DPIO_CHV_FRAC_DIV_EN; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val); - - /* Program digital lock detect threshold */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port)); - dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | - DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); - dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT); - if (!bestm2_frac) - dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val); - - /* Loop filter */ - if (vco == 5400000) { - loopfilter |= (0x3 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0x8 << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x1 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0x9; - } else if (vco <= 6200000) { - loopfilter |= (0x5 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0xB << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0x9; - } else if (vco <= 6480000) { - loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0x8; - } else { - /* Not supported. Apply the same limits as in the max case */ - loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0; - } - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter); - - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port)); - dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; - dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT); - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val); - - /* AFC Recal */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), - vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) | - DPIO_AFC_RECAL); - - vlv_dpio_put(dev_priv); -} - -/** - * vlv_force_pll_on - forcibly enable just the PLL - * @dev_priv: i915 private structure - * @pipe: pipe PLL to enable - * @dpll: PLL configuration - * - * Enable the PLL for @pipe using the supplied @dpll config. To be used - * in cases where we need the PLL enabled even when @pipe is not going to - * be enabled. - */ -int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, - const struct dpll *dpll) -{ - struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); - struct intel_crtc_state *pipe_config; - - pipe_config = intel_crtc_state_alloc(crtc); - if (!pipe_config) - return -ENOMEM; - - pipe_config->cpu_transcoder = (enum transcoder)pipe; - pipe_config->pixel_multiplier = 1; - pipe_config->dpll = *dpll; - - if (IS_CHERRYVIEW(dev_priv)) { - chv_compute_dpll(crtc, pipe_config); - chv_prepare_pll(crtc, pipe_config); - chv_enable_pll(crtc, pipe_config); - } else { - vlv_compute_dpll(crtc, pipe_config); - vlv_prepare_pll(crtc, pipe_config); - vlv_enable_pll(crtc, pipe_config); - } - - kfree(pipe_config); - - return 0; -} - -/** - * vlv_force_pll_off - forcibly disable just the PLL - * @dev_priv: i915 private structure - * @pipe: pipe PLL to disable - * - * Disable the PLL for @pipe. To be used in cases where we need - * the PLL enabled even when @pipe is not going to be enabled. - */ -void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - if (IS_CHERRYVIEW(dev_priv)) - chv_disable_pll(dev_priv, pipe); - else - vlv_disable_pll(dev_priv, pipe); -} - - - static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index c176c31c3ec2..1e0508bec3e5 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -585,9 +585,6 @@ void intel_cleanup_plane_fb(struct drm_plane *plane, void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, enum pipe pipe); -int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, - const struct dpll *dpll); -void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe); int lpt_get_iclkip(struct drm_i915_private *dev_priv); bool intel_fuzzy_clock_check(int clock1, int clock2); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index a338720cee2e..195857285600 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -50,6 +50,7 @@ #include "intel_dp_aux.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" +#include "intel_dpll.h" #include "intel_dpio_phy.h" #include "intel_fifo_underrun.h" #include "intel_hdcp.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 7ba7f315aaee..166e9a3a8c09 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -3,11 +3,13 @@ * Copyright © 2020 Intel Corporation */ #include +#include "intel_crtc.h" #include "intel_display_types.h" #include "intel_display.h" #include "intel_dpll.h" #include "intel_lvds.h" #include "intel_panel.h" +#include "intel_sideband.h" struct intel_limit { struct { @@ -1361,3 +1363,510 @@ intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv) else dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock; } + +static bool i9xx_has_pps(struct drm_i915_private *dev_priv) +{ + if (IS_I830(dev_priv)) + return false; + + return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv); +} + +void i9xx_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + i915_reg_t reg = DPLL(crtc->pipe); + u32 dpll = crtc_state->dpll_hw_state.dpll; + int i; + + assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + + /* PLL is protected by panel, make sure we can write it */ + if (i9xx_has_pps(dev_priv)) + assert_panel_unlocked(dev_priv, crtc->pipe); + + /* + * Apparently we need to have VGA mode enabled prior to changing + * the P1/P2 dividers. Otherwise the DPLL will keep using the old + * dividers, even though the register value does change. + */ + intel_de_write(dev_priv, reg, dpll & ~DPLL_VGA_MODE_DIS); + intel_de_write(dev_priv, reg, dpll); + + /* Wait for the clocks to stabilize. */ + intel_de_posting_read(dev_priv, reg); + udelay(150); + + if (INTEL_GEN(dev_priv) >= 4) { + intel_de_write(dev_priv, DPLL_MD(crtc->pipe), + crtc_state->dpll_hw_state.dpll_md); + } else { + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + intel_de_write(dev_priv, reg, dpll); + } + + /* We do this three times for luck */ + for (i = 0; i < 3; i++) { + intel_de_write(dev_priv, reg, dpll); + intel_de_posting_read(dev_priv, reg); + udelay(150); /* wait for warmup */ + } +} + +static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + u32 reg_val; + + /* + * PLLB opamp always calibrates to max value of 0x3f, force enable it + * and set it to a reasonable value instead. + */ + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val &= 0xffffff00; + reg_val |= 0x00000030; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val &= 0x00ffffff; + reg_val |= 0x8c000000; + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val &= 0xffffff00; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val &= 0x00ffffff; + reg_val |= 0xb0000000; + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); +} + +static void _vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); + intel_de_posting_read(dev_priv, DPLL(pipe)); + udelay(150); + + if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) + drm_err(&dev_priv->drm, "DPLL %d failed to lock\n", pipe); +} + +void vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); + + /* PLL is protected by panel, make sure we can write it */ + assert_panel_unlocked(dev_priv, pipe); + + if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) + _vlv_enable_pll(crtc, pipe_config); + + intel_de_write(dev_priv, DPLL_MD(pipe), + pipe_config->dpll_hw_state.dpll_md); + intel_de_posting_read(dev_priv, DPLL_MD(pipe)); +} + + +static void _chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + enum dpio_channel port = vlv_pipe_to_channel(pipe); + u32 tmp; + + vlv_dpio_get(dev_priv); + + /* Enable back the 10bit clock to display controller */ + tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + tmp |= DPIO_DCLKP_EN; + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); + + vlv_dpio_put(dev_priv); + + /* + * Need to wait > 100ns between dclkp clock enable bit and PLL enable. + */ + udelay(1); + + /* Enable PLL */ + intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); + + /* Check PLL is locked */ + if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) + drm_err(&dev_priv->drm, "PLL %d failed to lock\n", pipe); +} + +void chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); + + /* PLL is protected by panel, make sure we can write it */ + assert_panel_unlocked(dev_priv, pipe); + + if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) + _chv_enable_pll(crtc, pipe_config); + + if (pipe != PIPE_A) { + /* + * WaPixelRepeatModeFixForC0:chv + * + * DPLLCMD is AWOL. Use chicken bits to propagate + * the value from DPLLBMD to either pipe B or C. + */ + intel_de_write(dev_priv, CBR4_VLV, CBR_DPLLBMD_PIPE(pipe)); + intel_de_write(dev_priv, DPLL_MD(PIPE_B), + pipe_config->dpll_hw_state.dpll_md); + intel_de_write(dev_priv, CBR4_VLV, 0); + dev_priv->chv_dpll_md[pipe] = pipe_config->dpll_hw_state.dpll_md; + + /* + * DPLLB VGA mode also seems to cause problems. + * We should always have it disabled. + */ + drm_WARN_ON(&dev_priv->drm, + (intel_de_read(dev_priv, DPLL(PIPE_B)) & + DPLL_VGA_MODE_DIS) == 0); + } else { + intel_de_write(dev_priv, DPLL_MD(pipe), + pipe_config->dpll_hw_state.dpll_md); + intel_de_posting_read(dev_priv, DPLL_MD(pipe)); + } +} + +void vlv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum pipe pipe = crtc->pipe; + u32 mdiv; + u32 bestn, bestm1, bestm2, bestp1, bestp2; + u32 coreclk, reg_val; + + /* Enable Refclk */ + intel_de_write(dev_priv, DPLL(pipe), + pipe_config->dpll_hw_state.dpll & ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV)); + + /* No need to actually set up the DPLL with DSI */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + vlv_dpio_get(dev_priv); + + bestn = pipe_config->dpll.n; + bestm1 = pipe_config->dpll.m1; + bestm2 = pipe_config->dpll.m2; + bestp1 = pipe_config->dpll.p1; + bestp2 = pipe_config->dpll.p2; + + /* See eDP HDMI DPIO driver vbios notes doc */ + + /* PLL B needs special handling */ + if (pipe == PIPE_B) + vlv_pllb_recal_opamp(dev_priv, pipe); + + /* Set up Tx target for periodic Rcomp update */ + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); + + /* Disable target IRef on PLL */ + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); + reg_val &= 0x00ffffff; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); + + /* Disable fast lock */ + vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); + + /* Set idtafcrecal before PLL is enabled */ + mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); + mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); + mdiv |= ((bestn << DPIO_N_SHIFT)); + mdiv |= (1 << DPIO_K_SHIFT); + + /* + * Post divider depends on pixel clock rate, DAC vs digital (and LVDS, + * but we don't support that). + * Note: don't use the DAC post divider as it seems unstable. + */ + mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + + mdiv |= DPIO_ENABLE_CALIBRATION; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + + /* Set HBR and RBR LPF coefficients */ + if (pipe_config->port_clock == 162000 || + intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) || + intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI)) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + 0x009f0003); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + 0x00d0000f); + + if (intel_crtc_has_dp_encoder(pipe_config)) { + /* Use SSC source */ + if (pipe == PIPE_A) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df40000); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df70000); + } else { /* HDMI or VGA */ + /* Use bend source */ + if (pipe == PIPE_A) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df70000); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df40000); + } + + coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); + coreclk = (coreclk & 0x0000ff00) | 0x01c00000; + if (intel_crtc_has_dp_encoder(pipe_config)) + coreclk |= 0x01000000; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); + + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); + + vlv_dpio_put(dev_priv); +} + +void chv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum pipe pipe = crtc->pipe; + enum dpio_channel port = vlv_pipe_to_channel(pipe); + u32 loopfilter, tribuf_calcntr; + u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; + u32 dpio_val; + int vco; + + /* Enable Refclk and SSC */ + intel_de_write(dev_priv, DPLL(pipe), + pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE); + + /* No need to actually set up the DPLL with DSI */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + bestn = pipe_config->dpll.n; + bestm2_frac = pipe_config->dpll.m2 & 0x3fffff; + bestm1 = pipe_config->dpll.m1; + bestm2 = pipe_config->dpll.m2 >> 22; + bestp1 = pipe_config->dpll.p1; + bestp2 = pipe_config->dpll.p2; + vco = pipe_config->dpll.vco; + dpio_val = 0; + loopfilter = 0; + + vlv_dpio_get(dev_priv); + + /* p1 and p2 divider */ + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port), + 5 << DPIO_CHV_S1_DIV_SHIFT | + bestp1 << DPIO_CHV_P1_DIV_SHIFT | + bestp2 << DPIO_CHV_P2_DIV_SHIFT | + 1 << DPIO_CHV_K_DIV_SHIFT); + + /* Feedback post-divider - m2 */ + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2); + + /* Feedback refclk divider - n and m1 */ + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port), + DPIO_CHV_M1_DIV_BY_2 | + 1 << DPIO_CHV_N_DIV_SHIFT); + + /* M2 fraction division */ + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac); + + /* M2 fraction division enable */ + dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); + dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); + dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT); + if (bestm2_frac) + dpio_val |= DPIO_CHV_FRAC_DIV_EN; + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val); + + /* Program digital lock detect threshold */ + dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port)); + dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | + DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); + dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT); + if (!bestm2_frac) + dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val); + + /* Loop filter */ + if (vco == 5400000) { + loopfilter |= (0x3 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0x8 << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x1 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0x9; + } else if (vco <= 6200000) { + loopfilter |= (0x5 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0xB << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0x9; + } else if (vco <= 6480000) { + loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0x8; + } else { + /* Not supported. Apply the same limits as in the max case */ + loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0; + } + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter); + + dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port)); + dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; + dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT); + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val); + + /* AFC Recal */ + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), + vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) | + DPIO_AFC_RECAL); + + vlv_dpio_put(dev_priv); +} + +/** + * vlv_force_pll_on - forcibly enable just the PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to enable + * @dpll: PLL configuration + * + * Enable the PLL for @pipe using the supplied @dpll config. To be used + * in cases where we need the PLL enabled even when @pipe is not going to + * be enabled. + */ +int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, + const struct dpll *dpll) +{ + struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); + struct intel_crtc_state *pipe_config; + + pipe_config = intel_crtc_state_alloc(crtc); + if (!pipe_config) + return -ENOMEM; + + pipe_config->cpu_transcoder = (enum transcoder)pipe; + pipe_config->pixel_multiplier = 1; + pipe_config->dpll = *dpll; + + if (IS_CHERRYVIEW(dev_priv)) { + chv_compute_dpll(crtc, pipe_config); + chv_prepare_pll(crtc, pipe_config); + chv_enable_pll(crtc, pipe_config); + } else { + vlv_compute_dpll(crtc, pipe_config); + vlv_prepare_pll(crtc, pipe_config); + vlv_enable_pll(crtc, pipe_config); + } + + kfree(pipe_config); + + return 0; +} + +void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + u32 val; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, (enum transcoder)pipe); + + val = DPLL_INTEGRATED_REF_CLK_VLV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + if (pipe != PIPE_A) + val |= DPLL_INTEGRATED_CRI_CLK_VLV; + + intel_de_write(dev_priv, DPLL(pipe), val); + intel_de_posting_read(dev_priv, DPLL(pipe)); +} + +void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + enum dpio_channel port = vlv_pipe_to_channel(pipe); + u32 val; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, (enum transcoder)pipe); + + val = DPLL_SSC_REF_CLK_CHV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + if (pipe != PIPE_A) + val |= DPLL_INTEGRATED_CRI_CLK_VLV; + + intel_de_write(dev_priv, DPLL(pipe), val); + intel_de_posting_read(dev_priv, DPLL(pipe)); + + vlv_dpio_get(dev_priv); + + /* Disable 10bit clock to display controller */ + val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + val &= ~DPIO_DCLKP_EN; + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); + + vlv_dpio_put(dev_priv); +} + +void i9xx_disable_pll(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + /* Don't disable pipe or pipe PLLs if needed */ + if (IS_I830(dev_priv)) + return; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + + intel_de_write(dev_priv, DPLL(pipe), DPLL_VGA_MODE_DIS); + intel_de_posting_read(dev_priv, DPLL(pipe)); +} + + +/** + * vlv_force_pll_off - forcibly disable just the PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to disable + * + * Disable the PLL for @pipe. To be used in cases where we need + * the PLL enabled even when @pipe is not going to be enabled. + */ +void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + if (IS_CHERRYVIEW(dev_priv)) + chv_disable_pll(dev_priv, pipe); + else + vlv_disable_pll(dev_priv, pipe); +} diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index caf4615092e1..7ff4b0d29ed1 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -10,6 +10,7 @@ struct dpll; struct drm_i915_private; struct intel_crtc; struct intel_crtc_state; +enum pipe; void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv); int vlv_calc_dpll_params(int refclk, struct dpll *clock); @@ -20,4 +21,21 @@ void vlv_compute_dpll(struct intel_crtc *crtc, void chv_compute_dpll(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); +int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, + const struct dpll *dpll); +void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe); +void i9xx_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state); +void vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); +void chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); +void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); +void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); +void i9xx_disable_pll(const struct intel_crtc_state *crtc_state); +void vlv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); +void chv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); + #endif diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index c4867a8020a5..f20ba71f4307 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -6,6 +6,7 @@ #include "i915_drv.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dpll.h" #include "intel_pps.h" static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv, From patchwork Thu Feb 4 19:43:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068551 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3DEB2C433E0 for ; Thu, 4 Feb 2021 19:44:37 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DD66260235 for ; Thu, 4 Feb 2021 19:44:36 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DD66260235 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6F7966EE53; Thu, 4 Feb 2021 19:44:36 +0000 (UTC) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by gabe.freedesktop.org (Postfix) with ESMTPS id 452D26EE53 for ; Thu, 4 Feb 2021 19:44:35 +0000 (UTC) IronPort-SDR: MFT9rYHaPrt/LuWa4jZRAf+TYOfHTQ8I0xQPvlCdp9n6NhfqEDdO1RLq/KRNYTMMVBdHZbk/cz bKBfL1Fiaa2g== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="161072677" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="161072677" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:34 -0800 IronPort-SDR: /fOdt0sHCZcR2kKgpan4lbhCTcPmcQg2OfIrw11qScFQGXi7VXPqJyxxC83Ygr2vIPsqlAqmzO DObatIPLxHyA== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="415296531" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:32 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:25 +0200 Message-Id: <9f0cf421e2c73e67decde7b44c8d45799a8d3679.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 08/10] drm/i915: migrate i9xx plane get config 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie Migrate this code out like the skylake code. Signed-off-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/i9xx_plane.c | 119 +++++++++++++++++++ drivers/gpu/drm/i915/display/i9xx_plane.h | 4 + drivers/gpu/drm/i915/display/intel_display.c | 119 ------------------- 3 files changed, 123 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index d116dee201aa..0523e2c79d16 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -893,3 +893,122 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) return ERR_PTR(ret); } +static int i9xx_format_to_fourcc(int format) +{ + switch (format) { + case DISPPLANE_8BPP: + return DRM_FORMAT_C8; + case DISPPLANE_BGRA555: + return DRM_FORMAT_ARGB1555; + case DISPPLANE_BGRX555: + return DRM_FORMAT_XRGB1555; + case DISPPLANE_BGRX565: + return DRM_FORMAT_RGB565; + default: + case DISPPLANE_BGRX888: + return DRM_FORMAT_XRGB8888; + case DISPPLANE_RGBX888: + return DRM_FORMAT_XBGR8888; + case DISPPLANE_BGRA888: + return DRM_FORMAT_ARGB8888; + case DISPPLANE_RGBA888: + return DRM_FORMAT_ABGR8888; + case DISPPLANE_BGRX101010: + return DRM_FORMAT_XRGB2101010; + case DISPPLANE_RGBX101010: + return DRM_FORMAT_XBGR2101010; + case DISPPLANE_BGRA101010: + return DRM_FORMAT_ARGB2101010; + case DISPPLANE_RGBA101010: + return DRM_FORMAT_ABGR2101010; + case DISPPLANE_RGBX161616: + return DRM_FORMAT_XBGR16161616F; + } +} + +void +i9xx_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + enum pipe pipe; + u32 val, base, offset; + int fourcc, pixel_format; + unsigned int aligned_height; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + + if (!plane->get_hw_state(plane, &pipe)) + return; + + drm_WARN_ON(dev, pipe != crtc->pipe); + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) { + drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); + return; + } + + fb = &intel_fb->base; + + fb->dev = dev; + + val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + + if (INTEL_GEN(dev_priv) >= 4) { + if (val & DISPPLANE_TILED) { + plane_config->tiling = I915_TILING_X; + fb->modifier = I915_FORMAT_MOD_X_TILED; + } + + if (val & DISPPLANE_ROTATE_180) + plane_config->rotation = DRM_MODE_ROTATE_180; + } + + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B && + val & DISPPLANE_MIRROR) + plane_config->rotation |= DRM_MODE_REFLECT_X; + + pixel_format = val & DISPPLANE_PIXFORMAT_MASK; + fourcc = i9xx_format_to_fourcc(pixel_format); + fb->format = drm_format_info(fourcc); + + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { + offset = intel_de_read(dev_priv, DSPOFFSET(i9xx_plane)); + base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; + } else if (INTEL_GEN(dev_priv) >= 4) { + if (plane_config->tiling) + offset = intel_de_read(dev_priv, + DSPTILEOFF(i9xx_plane)); + else + offset = intel_de_read(dev_priv, + DSPLINOFF(i9xx_plane)); + base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; + } else { + base = intel_de_read(dev_priv, DSPADDR(i9xx_plane)); + } + plane_config->base = base; + + val = intel_de_read(dev_priv, PIPESRC(pipe)); + fb->width = ((val >> 16) & 0xfff) + 1; + fb->height = ((val >> 0) & 0xfff) + 1; + + val = intel_de_read(dev_priv, DSPSTRIDE(i9xx_plane)); + fb->pitches[0] = val & 0xffffffc0; + + aligned_height = intel_fb_align_height(fb, 0, fb->height); + + plane_config->size = fb->pitches[0] * aligned_height; + + drm_dbg_kms(&dev_priv->drm, + "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + crtc->base.name, plane->base.name, fb->width, fb->height, + fb->format->cpp[0] * 8, base, fb->pitches[0], + plane_config->size); + + plane_config->fb = intel_fb; +} + diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h index ca963c2a8457..027b66053984 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.h +++ b/drivers/gpu/drm/i915/display/i9xx_plane.h @@ -10,6 +10,8 @@ enum pipe; struct drm_i915_private; +struct intel_crtc; +struct intel_initial_plane_config; struct intel_plane; struct intel_plane_state; @@ -21,4 +23,6 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state); struct intel_plane * intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe); +void i9xx_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config); #endif diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 009f38cbd3c5..ef1e0f072d8f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2206,39 +2206,6 @@ intel_plane_compute_gtt(struct intel_plane_state *plane_state) return intel_plane_check_stride(plane_state); } -static int i9xx_format_to_fourcc(int format) -{ - switch (format) { - case DISPPLANE_8BPP: - return DRM_FORMAT_C8; - case DISPPLANE_BGRA555: - return DRM_FORMAT_ARGB1555; - case DISPPLANE_BGRX555: - return DRM_FORMAT_XRGB1555; - case DISPPLANE_BGRX565: - return DRM_FORMAT_RGB565; - default: - case DISPPLANE_BGRX888: - return DRM_FORMAT_XRGB8888; - case DISPPLANE_RGBX888: - return DRM_FORMAT_XBGR8888; - case DISPPLANE_BGRA888: - return DRM_FORMAT_ARGB8888; - case DISPPLANE_RGBA888: - return DRM_FORMAT_ABGR8888; - case DISPPLANE_BGRX101010: - return DRM_FORMAT_XRGB2101010; - case DISPPLANE_RGBX101010: - return DRM_FORMAT_XBGR2101010; - case DISPPLANE_BGRA101010: - return DRM_FORMAT_ARGB2101010; - case DISPPLANE_RGBA101010: - return DRM_FORMAT_ABGR2101010; - case DISPPLANE_RGBX161616: - return DRM_FORMAT_XBGR16161616F; - } -} - static struct i915_vma * initial_plane_vma(struct drm_i915_private *i915, struct intel_initial_plane_config *plane_config) @@ -5911,92 +5878,6 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); } -static void -i9xx_get_initial_plane_config(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - enum pipe pipe; - u32 val, base, offset; - int fourcc, pixel_format; - unsigned int aligned_height; - struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; - - if (!plane->get_hw_state(plane, &pipe)) - return; - - drm_WARN_ON(dev, pipe != crtc->pipe); - - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) { - drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); - return; - } - - fb = &intel_fb->base; - - fb->dev = dev; - - val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); - - if (INTEL_GEN(dev_priv) >= 4) { - if (val & DISPPLANE_TILED) { - plane_config->tiling = I915_TILING_X; - fb->modifier = I915_FORMAT_MOD_X_TILED; - } - - if (val & DISPPLANE_ROTATE_180) - plane_config->rotation = DRM_MODE_ROTATE_180; - } - - if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B && - val & DISPPLANE_MIRROR) - plane_config->rotation |= DRM_MODE_REFLECT_X; - - pixel_format = val & DISPPLANE_PIXFORMAT_MASK; - fourcc = i9xx_format_to_fourcc(pixel_format); - fb->format = drm_format_info(fourcc); - - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - offset = intel_de_read(dev_priv, DSPOFFSET(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; - } else if (INTEL_GEN(dev_priv) >= 4) { - if (plane_config->tiling) - offset = intel_de_read(dev_priv, - DSPTILEOFF(i9xx_plane)); - else - offset = intel_de_read(dev_priv, - DSPLINOFF(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; - } else { - base = intel_de_read(dev_priv, DSPADDR(i9xx_plane)); - } - plane_config->base = base; - - val = intel_de_read(dev_priv, PIPESRC(pipe)); - fb->width = ((val >> 16) & 0xfff) + 1; - fb->height = ((val >> 0) & 0xfff) + 1; - - val = intel_de_read(dev_priv, DSPSTRIDE(i9xx_plane)); - fb->pitches[0] = val & 0xffffffc0; - - aligned_height = intel_fb_align_height(fb, 0, fb->height); - - plane_config->size = fb->pitches[0] * aligned_height; - - drm_dbg_kms(&dev_priv->drm, - "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - crtc->base.name, plane->base.name, fb->width, fb->height, - fb->format->cpp[0] * 8, base, fb->pitches[0], - plane_config->size); - - plane_config->fb = intel_fb; -} - static void chv_crtc_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { From patchwork Thu Feb 4 19:43:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068553 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 997F2C433E0 for ; Thu, 4 Feb 2021 19:44:44 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3845160235 for ; Thu, 4 Feb 2021 19:44:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3845160235 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A8E4E6EE52; Thu, 4 Feb 2021 19:44:43 +0000 (UTC) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by gabe.freedesktop.org (Postfix) with ESMTPS id AF7C86EE52 for ; Thu, 4 Feb 2021 19:44:41 +0000 (UTC) IronPort-SDR: 2bc9Bjj06AHsnFFMP1LNaOsRCr3A+Zvdm7kmlN6b6LctZP4Thmw8gj/Hv4dn+ewsKSwo02UVEI jinFZGZIsgHA== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="181384312" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="181384312" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:41 -0800 IronPort-SDR: SArrM73gN+HcMQpDrp90gz1wGL4CZF6AWnkwhJvAwH0AF1JBbMo5V9WtqlhMqy7iGGMweKgvuI sjMF0Dp2xovg== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="576385454" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:37 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:26 +0200 Message-Id: <926cbdfc0bf4bc0ac7dee1b330dc1176dc50f391.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 09/10] drm/i915: refactor skylake scaler code into new file. 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie This moves the code from various places and consolidates it into one new file. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/icl_dsi.c | 1 + drivers/gpu/drm/i915/display/intel_atomic.c | 2 +- drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 429 +-------------- drivers/gpu/drm/i915/display/intel_display.h | 6 - drivers/gpu/drm/i915/display/intel_dp_mst.c | 1 + drivers/gpu/drm/i915/display/intel_sprite.c | 62 --- drivers/gpu/drm/i915/display/intel_sprite.h | 7 - drivers/gpu/drm/i915/display/skl_scaler.c | 497 ++++++++++++++++++ drivers/gpu/drm/i915/display/skl_scaler.h | 32 ++ .../drm/i915/display/skl_universal_plane.c | 1 + .../drm/i915/display/skl_universal_plane.h | 4 + drivers/gpu/drm/i915/display/vlv_dsi.c | 1 + 14 files changed, 541 insertions(+), 504 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/skl_scaler.c create mode 100644 drivers/gpu/drm/i915/display/skl_scaler.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 9388e09184fe..235679637d1c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -226,6 +226,7 @@ i915-y += \ display/intel_tc.o \ display/intel_vga.o \ display/i9xx_plane.o \ + display/skl_scaler.o \ display/skl_universal_plane.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 9eeec6fadec7..7ef6b89c79d9 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -35,6 +35,7 @@ #include "intel_dsi.h" #include "intel_panel.h" #include "intel_vdsc.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static int header_credits_available(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index e00fdc47c0eb..27f7d7109ca3 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -40,7 +40,7 @@ #include "intel_global_state.h" #include "intel_hdcp.h" #include "intel_psr.h" -#include "intel_sprite.h" +#include "skl_universal_plane.h" /** * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property. diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f4746c1edabe..3c4003605f93 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -54,6 +54,7 @@ #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vrr.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static const u8 index_to_dp_signal_levels[] = { diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index ef1e0f072d8f..d6046f2ab42e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -94,6 +94,7 @@ #include "intel_tc.h" #include "intel_vga.h" #include "i9xx_plane.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static void i9xx_crtc_clock_get(struct intel_crtc *crtc, @@ -2510,47 +2511,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, &to_intel_frontbuffer(fb)->bits); } -static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) -{ - struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, SKL_PS_CTRL(intel_crtc->pipe, id), 0); - intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(intel_crtc->pipe, id), 0); - intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -/* - * This function detaches (aka. unbinds) unused scalers in hardware - */ -static void skl_detach_scalers(const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - int i; - - /* loop through and disable scalers that aren't in use */ - for (i = 0; i < intel_crtc->num_scalers; i++) { - if (!scaler_state->scalers[i].in_use) - skl_detach_scaler(intel_crtc, i); - } -} - -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); - int i; - - for (i = 0; i < crtc->num_scalers; i++) - skl_detach_scaler(crtc, i); -} - unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) { @@ -3126,393 +3086,6 @@ static void cpt_verify_modeset(struct drm_i915_private *dev_priv, } } -/* - * The hardware phase 0.0 refers to the center of the pixel. - * We want to start from the top/left edge which is phase - * -0.5. That matches how the hardware calculates the scaling - * factors (from top-left of the first pixel to bottom-right - * of the last pixel, as opposed to the pixel centers). - * - * For 4:2:0 subsampled chroma planes we obviously have to - * adjust that so that the chroma sample position lands in - * the right spot. - * - * Note that for packed YCbCr 4:2:2 formats there is no way to - * control chroma siting. The hardware simply replicates the - * chroma samples for both of the luma samples, and thus we don't - * actually get the expected MPEG2 chroma siting convention :( - * The same behaviour is observed on pre-SKL platforms as well. - * - * Theory behind the formula (note that we ignore sub-pixel - * source coordinates): - * s = source sample position - * d = destination sample position - * - * Downscaling 4:1: - * -0.5 - * | 0.0 - * | | 1.5 (initial phase) - * | | | - * v v v - * | s | s | s | s | - * | d | - * - * Upscaling 1:4: - * -0.5 - * | -0.375 (initial phase) - * | | 0.0 - * | | | - * v v v - * | s | - * | d | d | d | d | - */ -u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited) -{ - int phase = -0x8000; - u16 trip = 0; - - if (chroma_cosited) - phase += (sub - 1) * 0x8000 / sub; - - phase += scale / (2 * sub); - - /* - * Hardware initial phase limited to [-0.5:1.5]. - * Since the max hardware scale factor is 3.0, we - * should never actually excdeed 1.0 here. - */ - WARN_ON(phase < -0x8000 || phase > 0x18000); - - if (phase < 0) - phase = 0x10000 + phase; - else - trip = PS_PHASE_TRIP; - - return ((phase >> 2) & PS_PHASE_MASK) | trip; -} - -#define SKL_MIN_SRC_W 8 -#define SKL_MAX_SRC_W 4096 -#define SKL_MIN_SRC_H 8 -#define SKL_MAX_SRC_H 4096 -#define SKL_MIN_DST_W 8 -#define SKL_MAX_DST_W 4096 -#define SKL_MIN_DST_H 8 -#define SKL_MAX_DST_H 4096 -#define ICL_MAX_SRC_W 5120 -#define ICL_MAX_SRC_H 4096 -#define ICL_MAX_DST_W 5120 -#define ICL_MAX_DST_H 4096 -#define SKL_MIN_YUV_420_SRC_W 16 -#define SKL_MIN_YUV_420_SRC_H 16 - -static int -skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, - unsigned int scaler_user, int *scaler_id, - int src_w, int src_h, int dst_w, int dst_h, - const struct drm_format_info *format, - u64 modifier, bool need_scaler) -{ - struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - struct intel_crtc *intel_crtc = - to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - - /* - * Src coordinates are already rotated by 270 degrees for - * the 90/270 degree plane rotation cases (to match the - * GTT mapping), hence no need to account for rotation here. - */ - if (src_w != dst_w || src_h != dst_h) - need_scaler = true; - - /* - * Scaling/fitting not supported in IF-ID mode in GEN9+ - * TODO: Interlace fetch mode doesn't support YUV420 planar formats. - * Once NV12 is enabled, handle it here while allocating scaler - * for NV12. - */ - if (INTEL_GEN(dev_priv) >= 9 && crtc_state->hw.enable && - need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { - drm_dbg_kms(&dev_priv->drm, - "Pipe/Plane scaling not supported with IF-ID mode\n"); - return -EINVAL; - } - - /* - * if plane is being disabled or scaler is no more required or force detach - * - free scaler binded to this plane/crtc - * - in order to do this, update crtc->scaler_usage - * - * Here scaler state in crtc_state is set free so that - * scaler can be assigned to other user. Actual register - * update to free the scaler is done in plane/panel-fit programming. - * For this purpose crtc/plane_state->scaler_id isn't reset here. - */ - if (force_detach || !need_scaler) { - if (*scaler_id >= 0) { - scaler_state->scaler_users &= ~(1 << scaler_user); - scaler_state->scalers[*scaler_id].in_use = 0; - - drm_dbg_kms(&dev_priv->drm, - "scaler_user index %u.%u: " - "Staged freeing scaler id %d scaler_users = 0x%x\n", - intel_crtc->pipe, scaler_user, *scaler_id, - scaler_state->scaler_users); - *scaler_id = -1; - } - return 0; - } - - if (format && intel_format_info_is_yuv_semiplanar(format, modifier) && - (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) { - drm_dbg_kms(&dev_priv->drm, - "Planar YUV: src dimensions not met\n"); - return -EINVAL; - } - - /* range checks */ - if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || - dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || - (INTEL_GEN(dev_priv) >= 11 && - (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H || - dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) || - (INTEL_GEN(dev_priv) < 11 && - (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || - dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) { - drm_dbg_kms(&dev_priv->drm, - "scaler_user index %u.%u: src %ux%u dst %ux%u " - "size is out of scaler range\n", - intel_crtc->pipe, scaler_user, src_w, src_h, - dst_w, dst_h); - return -EINVAL; - } - - /* mark this plane as a scaler user in crtc_state */ - scaler_state->scaler_users |= (1 << scaler_user); - drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " - "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n", - intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, - scaler_state->scaler_users); - - return 0; -} - -static int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) -{ - const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; - int width, height; - - if (crtc_state->pch_pfit.enabled) { - width = drm_rect_width(&crtc_state->pch_pfit.dst); - height = drm_rect_height(&crtc_state->pch_pfit.dst); - } else { - width = pipe_mode->crtc_hdisplay; - height = pipe_mode->crtc_vdisplay; - } - return skl_update_scaler(crtc_state, !crtc_state->hw.active, - SKL_CRTC_INDEX, - &crtc_state->scaler_state.scaler_id, - crtc_state->pipe_src_w, crtc_state->pipe_src_h, - width, height, NULL, 0, - crtc_state->pch_pfit.enabled); -} - -/** - * skl_update_scaler_plane - Stages update to scaler state for a given plane. - * @crtc_state: crtc's scaler state - * @plane_state: atomic plane state to update - * - * Return - * 0 - scaler_usage updated successfully - * error - requested scaling cannot be supported or other error condition - */ -static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) -{ - struct intel_plane *intel_plane = - to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); - struct drm_framebuffer *fb = plane_state->hw.fb; - int ret; - bool force_detach = !fb || !plane_state->uapi.visible; - bool need_scaler = false; - - /* Pre-gen11 and SDR planes always need a scaler for planar formats. */ - if (!icl_is_hdr_plane(dev_priv, intel_plane->id) && - fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - need_scaler = true; - - ret = skl_update_scaler(crtc_state, force_detach, - drm_plane_index(&intel_plane->base), - &plane_state->scaler_id, - drm_rect_width(&plane_state->uapi.src) >> 16, - drm_rect_height(&plane_state->uapi.src) >> 16, - drm_rect_width(&plane_state->uapi.dst), - drm_rect_height(&plane_state->uapi.dst), - fb ? fb->format : NULL, - fb ? fb->modifier : 0, - need_scaler); - - if (ret || plane_state->scaler_id < 0) - return ret; - - /* check colorkey */ - if (plane_state->ckey.flags) { - drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] scaling with color key not allowed", - intel_plane->base.base.id, - intel_plane->base.name); - return -EINVAL; - } - - /* Check src format */ - switch (fb->format->format) { - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_XYUV8888: - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU2101010: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - break; - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - if (INTEL_GEN(dev_priv) >= 11) - break; - fallthrough; - default: - drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n", - intel_plane->base.base.id, intel_plane->base.name, - fb->base.id, fb->format->format); - return -EINVAL; - } - - return 0; -} - -static int cnl_coef_tap(int i) -{ - return i % 7; -} - -static u16 cnl_nearest_filter_coef(int t) -{ - return t == 3 ? 0x0800 : 0x3000; -} - -/* - * Theory behind setting nearest-neighbor integer scaling: - * - * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. - * The letter represents the filter tap (D is the center tap) and the number - * represents the coefficient set for a phase (0-16). - * - * +------------+------------------------+------------------------+ - * |Index value | Data value coeffient 1 | Data value coeffient 2 | - * +------------+------------------------+------------------------+ - * | 00h | B0 | A0 | - * +------------+------------------------+------------------------+ - * | 01h | D0 | C0 | - * +------------+------------------------+------------------------+ - * | 02h | F0 | E0 | - * +------------+------------------------+------------------------+ - * | 03h | A1 | G0 | - * +------------+------------------------+------------------------+ - * | 04h | C1 | B1 | - * +------------+------------------------+------------------------+ - * | ... | ... | ... | - * +------------+------------------------+------------------------+ - * | 38h | B16 | A16 | - * +------------+------------------------+------------------------+ - * | 39h | D16 | C16 | - * +------------+------------------------+------------------------+ - * | 3Ah | F16 | C16 | - * +------------+------------------------+------------------------+ - * | 3Bh | Reserved | G16 | - * +------------+------------------------+------------------------+ - * - * To enable nearest-neighbor scaling: program scaler coefficents with - * the center tap (Dxx) values set to 1 and all other values set to 0 as per - * SCALER_COEFFICIENT_FORMAT - * - */ - -static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv, - enum pipe pipe, int id, int set) -{ - int i; - - intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), - PS_COEE_INDEX_AUTO_INC); - - for (i = 0; i < 17 * 7; i += 2) { - u32 tmp; - int t; - - t = cnl_coef_tap(i); - tmp = cnl_nearest_filter_coef(t); - - t = cnl_coef_tap(i + 1); - tmp |= cnl_nearest_filter_coef(t) << 16; - - intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set), - tmp); - } - - intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0); -} - -u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set) -{ - if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) { - return (PS_FILTER_PROGRAMMED | - PS_Y_VERT_FILTER_SELECT(set) | - PS_Y_HORZ_FILTER_SELECT(set) | - PS_UV_VERT_FILTER_SELECT(set) | - PS_UV_HORZ_FILTER_SELECT(set)); - } - - return PS_FILTER_MEDIUM; -} - -void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, - int id, int set, enum drm_scaling_filter filter) -{ - switch (filter) { - case DRM_SCALING_FILTER_DEFAULT: - break; - case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: - cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set); - break; - default: - MISSING_CASE(filter); - } -} - static void skl_pfit_enable(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 1e0508bec3e5..efb5d95791f9 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -609,12 +609,6 @@ enum intel_display_power_domain intel_legacy_aux_to_power_domain(enum aux_ch aux_ch); void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); - -u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_center); -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); -u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set); -void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, - int id, int set, enum drm_scaling_filter filter); void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state); int bdw_get_pipemisc_bpp(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b4621ed0127e..8e316146b6d1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -39,6 +39,7 @@ #include "intel_dp_mst.h" #include "intel_dpio_phy.h" #include "intel_hdcp.h" +#include "skl_scaler.h" static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 46fcb5b9983f..4cbdb8fd4bb1 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -138,68 +138,6 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) return 0; } -void -skl_program_scaler(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - enum pipe pipe = plane->pipe; - int scaler_id = plane_state->scaler_id; - const struct intel_scaler *scaler = - &crtc_state->scaler_state.scalers[scaler_id]; - int crtc_x = plane_state->uapi.dst.x1; - int crtc_y = plane_state->uapi.dst.y1; - u32 crtc_w = drm_rect_width(&plane_state->uapi.dst); - u32 crtc_h = drm_rect_height(&plane_state->uapi.dst); - u16 y_hphase, uv_rgb_hphase; - u16 y_vphase, uv_rgb_vphase; - int hscale, vscale; - u32 ps_ctrl; - - hscale = drm_rect_calc_hscale(&plane_state->uapi.src, - &plane_state->uapi.dst, - 0, INT_MAX); - vscale = drm_rect_calc_vscale(&plane_state->uapi.src, - &plane_state->uapi.dst, - 0, INT_MAX); - - /* TODO: handle sub-pixel coordinates */ - if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && - !icl_is_hdr_plane(dev_priv, plane->id)) { - y_hphase = skl_scaler_calc_phase(1, hscale, false); - y_vphase = skl_scaler_calc_phase(1, vscale, false); - - /* MPEG2 chroma siting convention */ - uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true); - uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false); - } else { - /* not used */ - y_hphase = 0; - y_vphase = 0; - - uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false); - uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false); - } - - ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0); - ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode; - - skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0, - plane_state->hw.scaling_filter); - - intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); - intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id), - PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); - intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id), - PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); - intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id), - (crtc_x << 16) | crtc_y); - intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id), - (crtc_w << 16) | crtc_h); -} - static void i9xx_plane_linear_gamma(u16 gamma[8]) { /* The points are not evenly spaced. */ diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 418897f953fc..f6989da2dc4b 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -45,10 +45,6 @@ static inline u8 icl_hdr_plane_mask(void) BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1); } -bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, - enum plane_id plane_id); -bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id); - int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, @@ -56,7 +52,4 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); -void skl_program_scaler(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); #endif /* __INTEL_SPRITE_H__ */ diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c new file mode 100644 index 000000000000..906a2fa79363 --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ +#include "intel_display_types.h" +#include "skl_scaler.h" +#include "skl_universal_plane.h" + +/* + * The hardware phase 0.0 refers to the center of the pixel. + * We want to start from the top/left edge which is phase + * -0.5. That matches how the hardware calculates the scaling + * factors (from top-left of the first pixel to bottom-right + * of the last pixel, as opposed to the pixel centers). + * + * For 4:2:0 subsampled chroma planes we obviously have to + * adjust that so that the chroma sample position lands in + * the right spot. + * + * Note that for packed YCbCr 4:2:2 formats there is no way to + * control chroma siting. The hardware simply replicates the + * chroma samples for both of the luma samples, and thus we don't + * actually get the expected MPEG2 chroma siting convention :( + * The same behaviour is observed on pre-SKL platforms as well. + * + * Theory behind the formula (note that we ignore sub-pixel + * source coordinates): + * s = source sample position + * d = destination sample position + * + * Downscaling 4:1: + * -0.5 + * | 0.0 + * | | 1.5 (initial phase) + * | | | + * v v v + * | s | s | s | s | + * | d | + * + * Upscaling 1:4: + * -0.5 + * | -0.375 (initial phase) + * | | 0.0 + * | | | + * v v v + * | s | + * | d | d | d | d | + */ +u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited) +{ + int phase = -0x8000; + u16 trip = 0; + + if (chroma_cosited) + phase += (sub - 1) * 0x8000 / sub; + + phase += scale / (2 * sub); + + /* + * Hardware initial phase limited to [-0.5:1.5]. + * Since the max hardware scale factor is 3.0, we + * should never actually excdeed 1.0 here. + */ + WARN_ON(phase < -0x8000 || phase > 0x18000); + + if (phase < 0) + phase = 0x10000 + phase; + else + trip = PS_PHASE_TRIP; + + return ((phase >> 2) & PS_PHASE_MASK) | trip; +} + +#define SKL_MIN_SRC_W 8 +#define SKL_MAX_SRC_W 4096 +#define SKL_MIN_SRC_H 8 +#define SKL_MAX_SRC_H 4096 +#define SKL_MIN_DST_W 8 +#define SKL_MAX_DST_W 4096 +#define SKL_MIN_DST_H 8 +#define SKL_MAX_DST_H 4096 +#define ICL_MAX_SRC_W 5120 +#define ICL_MAX_SRC_H 4096 +#define ICL_MAX_DST_W 5120 +#define ICL_MAX_DST_H 4096 +#define SKL_MIN_YUV_420_SRC_W 16 +#define SKL_MIN_YUV_420_SRC_H 16 + +static int +skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, + unsigned int scaler_user, int *scaler_id, + int src_w, int src_h, int dst_w, int dst_h, + const struct drm_format_info *format, + u64 modifier, bool need_scaler) +{ + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct intel_crtc *intel_crtc = + to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + + /* + * Src coordinates are already rotated by 270 degrees for + * the 90/270 degree plane rotation cases (to match the + * GTT mapping), hence no need to account for rotation here. + */ + if (src_w != dst_w || src_h != dst_h) + need_scaler = true; + + /* + * Scaling/fitting not supported in IF-ID mode in GEN9+ + * TODO: Interlace fetch mode doesn't support YUV420 planar formats. + * Once NV12 is enabled, handle it here while allocating scaler + * for NV12. + */ + if (INTEL_GEN(dev_priv) >= 9 && crtc_state->hw.enable && + need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + drm_dbg_kms(&dev_priv->drm, + "Pipe/Plane scaling not supported with IF-ID mode\n"); + return -EINVAL; + } + + /* + * if plane is being disabled or scaler is no more required or force detach + * - free scaler binded to this plane/crtc + * - in order to do this, update crtc->scaler_usage + * + * Here scaler state in crtc_state is set free so that + * scaler can be assigned to other user. Actual register + * update to free the scaler is done in plane/panel-fit programming. + * For this purpose crtc/plane_state->scaler_id isn't reset here. + */ + if (force_detach || !need_scaler) { + if (*scaler_id >= 0) { + scaler_state->scaler_users &= ~(1 << scaler_user); + scaler_state->scalers[*scaler_id].in_use = 0; + + drm_dbg_kms(&dev_priv->drm, + "scaler_user index %u.%u: " + "Staged freeing scaler id %d scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, *scaler_id, + scaler_state->scaler_users); + *scaler_id = -1; + } + return 0; + } + + if (format && intel_format_info_is_yuv_semiplanar(format, modifier) && + (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) { + drm_dbg_kms(&dev_priv->drm, + "Planar YUV: src dimensions not met\n"); + return -EINVAL; + } + + /* range checks */ + if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || + dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || + (INTEL_GEN(dev_priv) >= 11 && + (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H || + dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) || + (INTEL_GEN(dev_priv) < 11 && + (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || + dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) { + drm_dbg_kms(&dev_priv->drm, + "scaler_user index %u.%u: src %ux%u dst %ux%u " + "size is out of scaler range\n", + intel_crtc->pipe, scaler_user, src_w, src_h, + dst_w, dst_h); + return -EINVAL; + } + + /* mark this plane as a scaler user in crtc_state */ + scaler_state->scaler_users |= (1 << scaler_user); + drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " + "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, + scaler_state->scaler_users); + + return 0; +} + +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; + int width, height; + + if (crtc_state->pch_pfit.enabled) { + width = drm_rect_width(&crtc_state->pch_pfit.dst); + height = drm_rect_height(&crtc_state->pch_pfit.dst); + } else { + width = pipe_mode->crtc_hdisplay; + height = pipe_mode->crtc_vdisplay; + } + return skl_update_scaler(crtc_state, !crtc_state->hw.active, + SKL_CRTC_INDEX, + &crtc_state->scaler_state.scaler_id, + crtc_state->pipe_src_w, crtc_state->pipe_src_h, + width, height, NULL, 0, + crtc_state->pch_pfit.enabled); +} + +/** + * skl_update_scaler_plane - Stages update to scaler state for a given plane. + * @crtc_state: crtc's scaler state + * @plane_state: atomic plane state to update + * + * Return + * 0 - scaler_usage updated successfully + * error - requested scaling cannot be supported or other error condition + */ +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_plane *intel_plane = + to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); + struct drm_framebuffer *fb = plane_state->hw.fb; + int ret; + bool force_detach = !fb || !plane_state->uapi.visible; + bool need_scaler = false; + + /* Pre-gen11 and SDR planes always need a scaler for planar formats. */ + if (!icl_is_hdr_plane(dev_priv, intel_plane->id) && + fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + need_scaler = true; + + ret = skl_update_scaler(crtc_state, force_detach, + drm_plane_index(&intel_plane->base), + &plane_state->scaler_id, + drm_rect_width(&plane_state->uapi.src) >> 16, + drm_rect_height(&plane_state->uapi.src) >> 16, + drm_rect_width(&plane_state->uapi.dst), + drm_rect_height(&plane_state->uapi.dst), + fb ? fb->format : NULL, + fb ? fb->modifier : 0, + need_scaler); + + if (ret || plane_state->scaler_id < 0) + return ret; + + /* check colorkey */ + if (plane_state->ckey.flags) { + drm_dbg_kms(&dev_priv->drm, + "[PLANE:%d:%s] scaling with color key not allowed", + intel_plane->base.base.id, + intel_plane->base.name); + return -EINVAL; + } + + /* Check src format */ + switch (fb->format->format) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + break; + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + if (INTEL_GEN(dev_priv) >= 11) + break; + fallthrough; + default: + drm_dbg_kms(&dev_priv->drm, + "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n", + intel_plane->base.base.id, intel_plane->base.name, + fb->base.id, fb->format->format); + return -EINVAL; + } + + return 0; +} + +static int cnl_coef_tap(int i) +{ + return i % 7; +} + +static u16 cnl_nearest_filter_coef(int t) +{ + return t == 3 ? 0x0800 : 0x3000; +} + +/* + * Theory behind setting nearest-neighbor integer scaling: + * + * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. + * The letter represents the filter tap (D is the center tap) and the number + * represents the coefficient set for a phase (0-16). + * + * +------------+------------------------+------------------------+ + * |Index value | Data value coeffient 1 | Data value coeffient 2 | + * +------------+------------------------+------------------------+ + * | 00h | B0 | A0 | + * +------------+------------------------+------------------------+ + * | 01h | D0 | C0 | + * +------------+------------------------+------------------------+ + * | 02h | F0 | E0 | + * +------------+------------------------+------------------------+ + * | 03h | A1 | G0 | + * +------------+------------------------+------------------------+ + * | 04h | C1 | B1 | + * +------------+------------------------+------------------------+ + * | ... | ... | ... | + * +------------+------------------------+------------------------+ + * | 38h | B16 | A16 | + * +------------+------------------------+------------------------+ + * | 39h | D16 | C16 | + * +------------+------------------------+------------------------+ + * | 3Ah | F16 | C16 | + * +------------+------------------------+------------------------+ + * | 3Bh | Reserved | G16 | + * +------------+------------------------+------------------------+ + * + * To enable nearest-neighbor scaling: program scaler coefficents with + * the center tap (Dxx) values set to 1 and all other values set to 0 as per + * SCALER_COEFFICIENT_FORMAT + * + */ + +static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv, + enum pipe pipe, int id, int set) +{ + int i; + + intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), + PS_COEE_INDEX_AUTO_INC); + + for (i = 0; i < 17 * 7; i += 2) { + u32 tmp; + int t; + + t = cnl_coef_tap(i); + tmp = cnl_nearest_filter_coef(t); + + t = cnl_coef_tap(i + 1); + tmp |= cnl_nearest_filter_coef(t) << 16; + + intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set), + tmp); + } + + intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0); +} + +u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set) +{ + if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) { + return (PS_FILTER_PROGRAMMED | + PS_Y_VERT_FILTER_SELECT(set) | + PS_Y_HORZ_FILTER_SELECT(set) | + PS_UV_VERT_FILTER_SELECT(set) | + PS_UV_HORZ_FILTER_SELECT(set)); + } + + return PS_FILTER_MEDIUM; +} + +void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, + int id, int set, enum drm_scaling_filter filter) +{ + switch (filter) { + case DRM_SCALING_FILTER_DEFAULT: + break; + case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: + cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set); + break; + default: + MISSING_CASE(filter); + } +} + +void +skl_program_scaler(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + enum pipe pipe = plane->pipe; + int scaler_id = plane_state->scaler_id; + const struct intel_scaler *scaler = + &crtc_state->scaler_state.scalers[scaler_id]; + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + u32 crtc_w = drm_rect_width(&plane_state->uapi.dst); + u32 crtc_h = drm_rect_height(&plane_state->uapi.dst); + u16 y_hphase, uv_rgb_hphase; + u16 y_vphase, uv_rgb_vphase; + int hscale, vscale; + u32 ps_ctrl; + + hscale = drm_rect_calc_hscale(&plane_state->uapi.src, + &plane_state->uapi.dst, + 0, INT_MAX); + vscale = drm_rect_calc_vscale(&plane_state->uapi.src, + &plane_state->uapi.dst, + 0, INT_MAX); + + /* TODO: handle sub-pixel coordinates */ + if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && + !icl_is_hdr_plane(dev_priv, plane->id)) { + y_hphase = skl_scaler_calc_phase(1, hscale, false); + y_vphase = skl_scaler_calc_phase(1, vscale, false); + + /* MPEG2 chroma siting convention */ + uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true); + uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false); + } else { + /* not used */ + y_hphase = 0; + y_vphase = 0; + + uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false); + uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false); + } + + ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0); + ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode; + + skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0, + plane_state->hw.scaling_filter); + + intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); + intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id), + PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); + intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id), + PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); + intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id), + (crtc_x << 16) | crtc_y); + intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id), + (crtc_w << 16) | crtc_h); +} + +static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + intel_de_write_fw(dev_priv, SKL_PS_CTRL(intel_crtc->pipe, id), 0); + intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(intel_crtc->pipe, id), 0); + intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +/* + * This function detaches (aka. unbinds) unused scalers in hardware + */ +void skl_detach_scalers(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); + const struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + int i; + + /* loop through and disable scalers that aren't in use */ + for (i = 0; i < intel_crtc->num_scalers; i++) { + if (!scaler_state->scalers[i].in_use) + skl_detach_scaler(intel_crtc, i); + } +} + +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); + int i; + + for (i = 0; i < crtc->num_scalers; i++) + skl_detach_scaler(crtc, i); +} diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h b/drivers/gpu/drm/i915/display/skl_scaler.h new file mode 100644 index 000000000000..16bf829357c0 --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_scaler.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ +#ifndef INTEL_SCALER_H +#define INTEL_SCALER_H + +#include + +enum drm_scaling_filter; +struct drm_i915_private; +struct intel_crtc_state; +struct intel_plane_state; +struct intel_plane; +enum pipe; + +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); + +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state); + +u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_center); +u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set); +void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, + int id, int set, enum drm_scaling_filter filter); + +void skl_program_scaler(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state); +void skl_detach_scalers(const struct intel_crtc_state *crtc_state); +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); +#endif diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 4ae1a2ef29ec..05bce1b775bf 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -14,6 +14,7 @@ #include "intel_pm.h" #include "intel_psr.h" #include "intel_sprite.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static const u32 skl_plane_formats[] = { diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h index 70eb5010cd28..818266653630 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h @@ -30,4 +30,8 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane); int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, int *x, int *y, u32 *offset); +bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, + enum plane_id plane_id); +bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id); + #endif diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index f94025ec603a..1059a26c1f58 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -38,6 +38,7 @@ #include "intel_fifo_underrun.h" #include "intel_panel.h" #include "intel_sideband.h" +#include "skl_scaler.h" /* return pixels in terms of txbyteclkhs */ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, From patchwork Thu Feb 4 19:43:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 12068555 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84D53C433DB for ; Thu, 4 Feb 2021 19:44:50 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 364F964F45 for ; Thu, 4 Feb 2021 19:44:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 364F964F45 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 98A706EE54; Thu, 4 Feb 2021 19:44:49 +0000 (UTC) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by gabe.freedesktop.org (Postfix) with ESMTPS id 198AE6EE58 for ; Thu, 4 Feb 2021 19:44:48 +0000 (UTC) IronPort-SDR: frLl68QUVcQDf/eb/6BBu5BRz8RgEjFN1APbOOWXWrZeATMkl+xUAJNJqy0tfEpqtrY12kc+VD htSBVLPWbXtg== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="266147062" X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="266147062" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:47 -0800 IronPort-SDR: VY6mqAyPFZU6EuY3BkB97RhY11RZCE9CAbYksPk5RWbyByu4WYCCcCoKr2YNo4NBX6DH5F1UXx EDV04H/s7LKA== X-IronPort-AV: E=Sophos;i="5.81,153,1610438400"; d="scan'208";a="407316076" Received: from dbmayer-mobl.ger.corp.intel.com (HELO localhost) ([10.252.53.1]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 11:44:44 -0800 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Thu, 4 Feb 2021 21:43:27 +0200 Message-Id: <97213f2008ee09e22e97160b8d4923d5c60c4965.1612467466.git.jani.nikula@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v11 10/10] drm/i915: move ddi pll state get to dpll mgr 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, Dave Airlie Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Dave Airlie This just migrates the hsw+ code to a better place. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 219 +---------------- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 223 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dpll_mgr.h | 2 + 3 files changed, 226 insertions(+), 218 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d6046f2ab42e..7b7f4af701ac 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6579,212 +6579,6 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc, return ret; } -static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT; - enum phy phy = intel_port_to_phy(dev_priv, port); - struct icl_port_dpll *port_dpll; - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - u32 clk_sel; - - clk_sel = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)) & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - id = DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy); - - if (WARN_ON(id > DPLL_ID_DG1_DPLL3)) - return; - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - port_dpll = &pipe_config->icl_port_dplls[port_dpll_id]; - - port_dpll->pll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &port_dpll->hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); - - icl_set_active_port_dpll(pipe_config, port_dpll_id); -} - -static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - enum phy phy = intel_port_to_phy(dev_priv, port); - enum icl_port_dpll_id port_dpll_id; - struct icl_port_dpll *port_dpll; - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - i915_reg_t reg; - u32 temp; - - if (intel_phy_is_combo(dev_priv, phy)) { - u32 mask, shift; - - if (IS_ALDERLAKE_S(dev_priv)) { - reg = ADLS_DPCLKA_CFGCR(phy); - mask = ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy); - shift = ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy); - } else if (IS_ROCKETLAKE(dev_priv)) { - reg = ICL_DPCLKA_CFGCR0; - mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - shift = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); - } else { - reg = ICL_DPCLKA_CFGCR0; - mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - shift = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); - } - - temp = intel_de_read(dev_priv, reg) & mask; - id = temp >> shift; - port_dpll_id = ICL_PORT_DPLL_DEFAULT; - } else if (intel_phy_is_tc(dev_priv, phy)) { - u32 clk_sel = intel_de_read(dev_priv, DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK; - - if (clk_sel == DDI_CLK_SEL_MG) { - id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv, - port)); - port_dpll_id = ICL_PORT_DPLL_MG_PHY; - } else { - drm_WARN_ON(&dev_priv->drm, - clk_sel < DDI_CLK_SEL_TBT_162); - id = DPLL_ID_ICL_TBTPLL; - port_dpll_id = ICL_PORT_DPLL_DEFAULT; - } - } else { - drm_WARN(&dev_priv->drm, 1, "Invalid port %x\n", port); - return; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - port_dpll = &pipe_config->icl_port_dplls[port_dpll_id]; - - port_dpll->pll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &port_dpll->hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); - - icl_set_active_port_dpll(pipe_config, port_dpll_id); -} - -static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - u32 temp; - - temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); - id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port); - - if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2)) - return; - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - -static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv, - enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - - switch (port) { - case PORT_A: - id = DPLL_ID_SKL_DPLL0; - break; - case PORT_B: - id = DPLL_ID_SKL_DPLL1; - break; - case PORT_C: - id = DPLL_ID_SKL_DPLL2; - break; - default: - drm_err(&dev_priv->drm, "Incorrect port type\n"); - return; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - -static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - u32 temp; - - temp = intel_de_read(dev_priv, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port); - id = temp >> (port * 3 + 1); - - if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL3)) - return; - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - -static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - u32 ddi_pll_sel = intel_de_read(dev_priv, PORT_CLK_SEL(port)); - bool pll_active; - - switch (ddi_pll_sel) { - case PORT_CLK_SEL_WRPLL1: - id = DPLL_ID_WRPLL1; - break; - case PORT_CLK_SEL_WRPLL2: - id = DPLL_ID_WRPLL2; - break; - case PORT_CLK_SEL_SPLL: - id = DPLL_ID_SPLL; - break; - case PORT_CLK_SEL_LCPLL_810: - id = DPLL_ID_LCPLL_810; - break; - case PORT_CLK_SEL_LCPLL_1350: - id = DPLL_ID_LCPLL_1350; - break; - case PORT_CLK_SEL_LCPLL_2700: - id = DPLL_ID_LCPLL_2700; - break; - default: - MISSING_CASE(ddi_pll_sel); - fallthrough; - case PORT_CLK_SEL_NONE: - return; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - static bool hsw_get_transcoder_state(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config, struct intel_display_power_domain_set *power_domain_set) @@ -6941,18 +6735,7 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc, port = TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp); } - if (IS_DG1(dev_priv)) - dg1_get_ddi_pll(dev_priv, port, pipe_config); - else if (INTEL_GEN(dev_priv) >= 11) - icl_get_ddi_pll(dev_priv, port, pipe_config); - else if (IS_CANNONLAKE(dev_priv)) - cnl_get_ddi_pll(dev_priv, port, pipe_config); - else if (IS_GEN9_LP(dev_priv)) - bxt_get_ddi_pll(dev_priv, port, pipe_config); - else if (IS_GEN9_BC(dev_priv)) - skl_get_ddi_pll(dev_priv, port, pipe_config); - else - hsw_get_ddi_pll(dev_priv, port, pipe_config); + intel_get_ddi_pll(dev_priv, port, pipe_config); /* * Haswell has only FDI/PCH transcoder A. It is which is connected to diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 529b1d569af2..cdbdc6508eaa 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4670,3 +4670,226 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, hw_state->fp1); } } + +static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT; + enum phy phy = intel_port_to_phy(dev_priv, port); + struct icl_port_dpll *port_dpll; + struct intel_shared_dpll *pll; + enum intel_dpll_id id; + bool pll_active; + u32 clk_sel; + + clk_sel = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)) & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + id = DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy); + + if (WARN_ON(id > DPLL_ID_DG1_DPLL3)) + return; + + pll = intel_get_shared_dpll_by_id(dev_priv, id); + port_dpll = &pipe_config->icl_port_dplls[port_dpll_id]; + + port_dpll->pll = pll; + pll_active = intel_dpll_get_hw_state(dev_priv, pll, + &port_dpll->hw_state); + drm_WARN_ON(&dev_priv->drm, !pll_active); + + icl_set_active_port_dpll(pipe_config, port_dpll_id); +} + +static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + enum phy phy = intel_port_to_phy(dev_priv, port); + enum icl_port_dpll_id port_dpll_id; + struct icl_port_dpll *port_dpll; + struct intel_shared_dpll *pll; + enum intel_dpll_id id; + bool pll_active; + i915_reg_t reg; + u32 temp; + + if (intel_phy_is_combo(dev_priv, phy)) { + u32 mask, shift; + + if (IS_ALDERLAKE_S(dev_priv)) { + reg = ADLS_DPCLKA_CFGCR(phy); + mask = ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy); + shift = ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy); + } else if (IS_ROCKETLAKE(dev_priv)) { + reg = ICL_DPCLKA_CFGCR0; + mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + shift = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); + } else { + reg = ICL_DPCLKA_CFGCR0; + mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + shift = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); + } + + temp = intel_de_read(dev_priv, reg) & mask; + id = temp >> shift; + port_dpll_id = ICL_PORT_DPLL_DEFAULT; + } else if (intel_phy_is_tc(dev_priv, phy)) { + u32 clk_sel = intel_de_read(dev_priv, DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK; + + if (clk_sel == DDI_CLK_SEL_MG) { + id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv, + port)); + port_dpll_id = ICL_PORT_DPLL_MG_PHY; + } else { + drm_WARN_ON(&dev_priv->drm, + clk_sel < DDI_CLK_SEL_TBT_162); + id = DPLL_ID_ICL_TBTPLL; + port_dpll_id = ICL_PORT_DPLL_DEFAULT; + } + } else { + drm_WARN(&dev_priv->drm, 1, "Invalid port %x\n", port); + return; + } + + pll = intel_get_shared_dpll_by_id(dev_priv, id); + port_dpll = &pipe_config->icl_port_dplls[port_dpll_id]; + + port_dpll->pll = pll; + pll_active = intel_dpll_get_hw_state(dev_priv, pll, + &port_dpll->hw_state); + drm_WARN_ON(&dev_priv->drm, !pll_active); + + icl_set_active_port_dpll(pipe_config, port_dpll_id); +} + +static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id id; + bool pll_active; + u32 temp; + + temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); + id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port); + + if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2)) + return; + + pll = intel_get_shared_dpll_by_id(dev_priv, id); + + pipe_config->shared_dpll = pll; + pll_active = intel_dpll_get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state); + drm_WARN_ON(&dev_priv->drm, !pll_active); +} + +static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv, + enum port port, + struct intel_crtc_state *pipe_config) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id id; + bool pll_active; + + switch (port) { + case PORT_A: + id = DPLL_ID_SKL_DPLL0; + break; + case PORT_B: + id = DPLL_ID_SKL_DPLL1; + break; + case PORT_C: + id = DPLL_ID_SKL_DPLL2; + break; + default: + drm_err(&dev_priv->drm, "Incorrect port type\n"); + return; + } + + pll = intel_get_shared_dpll_by_id(dev_priv, id); + + pipe_config->shared_dpll = pll; + pll_active = intel_dpll_get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state); + drm_WARN_ON(&dev_priv->drm, !pll_active); +} + +static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id id; + bool pll_active; + u32 temp; + + temp = intel_de_read(dev_priv, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port); + id = temp >> (port * 3 + 1); + + if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL3)) + return; + + pll = intel_get_shared_dpll_by_id(dev_priv, id); + + pipe_config->shared_dpll = pll; + pll_active = intel_dpll_get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state); + drm_WARN_ON(&dev_priv->drm, !pll_active); +} + +static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + struct intel_shared_dpll *pll; + enum intel_dpll_id id; + u32 ddi_pll_sel = intel_de_read(dev_priv, PORT_CLK_SEL(port)); + bool pll_active; + + switch (ddi_pll_sel) { + case PORT_CLK_SEL_WRPLL1: + id = DPLL_ID_WRPLL1; + break; + case PORT_CLK_SEL_WRPLL2: + id = DPLL_ID_WRPLL2; + break; + case PORT_CLK_SEL_SPLL: + id = DPLL_ID_SPLL; + break; + case PORT_CLK_SEL_LCPLL_810: + id = DPLL_ID_LCPLL_810; + break; + case PORT_CLK_SEL_LCPLL_1350: + id = DPLL_ID_LCPLL_1350; + break; + case PORT_CLK_SEL_LCPLL_2700: + id = DPLL_ID_LCPLL_2700; + break; + default: + MISSING_CASE(ddi_pll_sel); + fallthrough; + case PORT_CLK_SEL_NONE: + return; + } + + pll = intel_get_shared_dpll_by_id(dev_priv, id); + + pipe_config->shared_dpll = pll; + pll_active = intel_dpll_get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state); + drm_WARN_ON(&dev_priv->drm, !pll_active); +} + +void intel_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config) +{ + if (IS_DG1(dev_priv)) + dg1_get_ddi_pll(dev_priv, port, pipe_config); + else if (INTEL_GEN(dev_priv) >= 11) + icl_get_ddi_pll(dev_priv, port, pipe_config); + else if (IS_CANNONLAKE(dev_priv)) + cnl_get_ddi_pll(dev_priv, port, pipe_config); + else if (IS_GEN9_LP(dev_priv)) + bxt_get_ddi_pll(dev_priv, port, pipe_config); + else if (IS_GEN9_BC(dev_priv)) + skl_get_ddi_pll(dev_priv, port, pipe_config); + else + hsw_get_ddi_pll(dev_priv, port, pipe_config); +} diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 2eb7618ef957..fe4e99355d6d 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -418,4 +418,6 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port); bool intel_dpll_is_combophy(enum intel_dpll_id id); +void intel_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, + struct intel_crtc_state *pipe_config); #endif /* _INTEL_DPLL_MGR_H_ */