Received: by 2002:a05:7412:bbc7:b0:fc:a2b0:25d7 with SMTP id kh7csp2213405rdb; Sun, 4 Feb 2024 21:52:04 -0800 (PST) X-Google-Smtp-Source: AGHT+IGrSTT1wFkkRLZY9zz79tLIgzJH30PKthwSnSzo01m2zrd7jPLIHC5RLwU/q5WRifx7Y5g0 X-Received: by 2002:a05:6a20:394b:b0:19e:840f:34d9 with SMTP id r11-20020a056a20394b00b0019e840f34d9mr4203323pzg.29.1707112324451; Sun, 04 Feb 2024 21:52:04 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707112324; cv=pass; d=google.com; s=arc-20160816; b=ktOZoLHfT/r9EfVxWRmL/DQeZ4nQXHF0t4GHCOVS0+m82ed2C4FkWnGU9zUw1J+zRO h5FYKI+wqK+HCD3Ensv8tdY18OVzn6tMvR8yZgFj8P8VnGEauhsRJDl0Kh2kift+fzEE djSK8H/mAp5pEvCaKmhPyuiNU5iy5lTSA1PjMKhTREBvhoCs3x0utA1S5nmGm+w2kbRw 6ObHKu6s3k6mSJhqCNr5x5tEWsTWEyLw3WkH0hyOpBMF49X9ClQ5x6gtwGCc562R2mjs 5R91Tg/4e+5aFXTvoIwcxBRLunATY/MlYK/EibPrtKoqK/6gngDfHG/wOOh9uWkExTPU e7UA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=Zj4kF6Nfh/PvZmHs+5yXsdA7oEfEbh/7MGvnWp+xHbU=; fh=04aH0GpmAzr1RWpPlWz/XR22ODbUQWUcFTUiY7Akd7I=; b=0Hr3mORluzL0XrOwWVoex+mQRXjGGqGE3YokcRnfkC9Y83/7/Qrv2TXRC5nankHSKz mc+pfYP9QqsRLq/zjTkBGUtRIjeTPB5HPqFu01YM8UCpb2i1i+4qWQvTF7sVPHe0efqM +4Ni7kOeonIQdtGQcIyKbDJMyRB9RKexfnGWaGdo+g3MExM3KGdBEoRKcnQ9iRuHFdRF LmDTuntq7vPlqDBnB/IzDVqnASmuuWwTsxWztJW3wIKhC58SPznqYNwy32g6woQpcPGF Saq2OZ2HUaXKi/Jy2wKp/fZox1NdnAVbAS1/AFiqPJsQiQf3nq8jNjwG7lwUV2zahgEp dEcQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@mediatek.com header.s=dk header.b=qPfXc4XO; arc=pass (i=1 spf=pass spfdomain=mediatek.com dkim=pass dkdomain=mediatek.com dmarc=pass fromdomain=mediatek.com); spf=pass (google.com: domain of linux-kernel+bounces-52057-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-52057-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=mediatek.com X-Forwarded-Encrypted: i=1; AJvYcCVl/GRj5NkbNEuEKYKhHuxEbcFqL73svaKO5ZTxmsaic1OeYjtwJmXhbPbZ1mCREbP9z1CX0lNn8maeMa3TeSd0geudRvXD5wp1742NoA== Return-Path: Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [2604:1380:40f1:3f00::1]) by mx.google.com with ESMTPS id m125-20020a633f83000000b005dc189d320csi1367215pga.399.2024.02.04.21.52.03 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 04 Feb 2024 21:52:04 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-52057-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) client-ip=2604:1380:40f1:3f00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@mediatek.com header.s=dk header.b=qPfXc4XO; arc=pass (i=1 spf=pass spfdomain=mediatek.com dkim=pass dkdomain=mediatek.com dmarc=pass fromdomain=mediatek.com); spf=pass (google.com: domain of linux-kernel+bounces-52057-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-52057-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=mediatek.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id 66AC9B2226D for ; Mon, 5 Feb 2024 05:51:58 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6A237C8E0; Mon, 5 Feb 2024 05:51:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="qPfXc4XO" Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 29700BA28 for ; Mon, 5 Feb 2024 05:51:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707112296; cv=none; b=sqN210KXe6jdDeXmreomYHspRDliHSU97JVlc95ZRWr6X8Oj6+VlFs9Mr5B8maxPlwm9Gy0fneRJ640rGGJ6sUEPkQ7g//MqGRZFCsAg19mPcGONJ9MsFXdgkJRvZALMMeGGc8NWuPhqnwtN8kqWG2poy86BMWWGVtnuCgCJjtk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707112296; c=relaxed/simple; bh=wIScT4wzzBHEmeQcB8XUur7sbW7gt+B0KLEmsgKQ5Bk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eNPvqweHc4f621W5zEhI1HNVglsT12fAPWirpHQXHWSRY+yZedZodUfkG+LMx3C3fEwIuod6Vq8/AzGFJLEnS8k5EATfP6/C6S92RvdwMEwaj7eCUhYQPMHF6gOcHqS3ujpxO2+DBjU6I8O5ycQD3uiie+ln7+78OlPCpv++o6s= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=qPfXc4XO; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com X-UUID: 9afbb8c6c3ea11ee9e680517dc993faa-20240205 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=Zj4kF6Nfh/PvZmHs+5yXsdA7oEfEbh/7MGvnWp+xHbU=; b=qPfXc4XOSXvOQkCx18AzvTQkpZUBnA8l0Db4gTjqtmp2dyyt6UI6miqsiA5R/0LT8ddjtrDmKZ0iZ90oSvsQMGzBvOfdh5HNpPqb9qmkA87toieSpr742GpEQDJzm/sc0/WLTYFGgfKSkCZ8pjuTf3YckPIYxtWZygQkdEBuEUs=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.37,REQID:c1d94499-2061-457c-9b04-acb7ced05c6e,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:6f543d0,CLOUDID:c892068f-e2c0-40b0-a8fe-7c7e47299109,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULS X-UUID: 9afbb8c6c3ea11ee9e680517dc993faa-20240205 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 249598753; Mon, 05 Feb 2024 13:51:28 +0800 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs11n2.mediatek.inc (172.21.101.187) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Mon, 5 Feb 2024 13:51:27 +0800 Received: from mszsdhlt06.gcn.mediatek.inc (10.16.6.206) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Mon, 5 Feb 2024 13:51:27 +0800 From: mac.shen To: , , , , , , CC: , , , , , Subject: [PATCH v2 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x feature for DisplayPort Date: Mon, 5 Feb 2024 13:50:38 +0800 Message-ID: <20240205055055.25340-4-mac.shen@mediatek.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240205055055.25340-1-mac.shen@mediatek.com> References: <20240205055055.25340-1-mac.shen@mediatek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-MTK: N Add HDCP1.x feature for DisplayPort. If the sink support HDCP1.X only, the feature will do HDCP1.x authentication when userspace request the kernel protect with HDCP_Content_Type property as DRM_MODE_HDCP_CONTENT_TYPE0. Changes in v2: - remove useless code - remove the prefix 'mdrv' - do HDCP1.x authentication when userspace request the kernel protect future content communicated per suggestion from the previous thread: https://lore.kernel.org/all/8fff59b5567449d8201dd1138c8 fa9218a545c46.camel@mediatek.com/ Signed-off-by: mac.shen --- drivers/gpu/drm/mediatek/Makefile | 1 + drivers/gpu/drm/mediatek/mtk_dp.c | 33 +- drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c | 589 +++++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h | 46 ++ drivers/gpu/drm/mediatek/mtk_dp_reg.h | 3 + 5 files changed, 669 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 50ea069b047e..9738235f76b8 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -27,6 +27,7 @@ mediatek-drm-hdmi-objs := mtk_cec.o \ obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o mtk-dp-objs := tlc_dp_hdcp.o \ + mtk_dp_hdcp1x.o \ mtk_dp_hdcp2.o \ mtk_dp.o diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 7ff72f15528b..8cd7562dab7a 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -33,6 +33,7 @@ #include "mtk_dp.h" #include "mtk_dp_reg.h" +#include "mtk_dp_hdcp1x.h" #include "mtk_dp_hdcp2.h" #define MTK_DP_SIP_CONTROL_AARCH32 MTK_SIP_SMC_CMD(0x523) @@ -1811,6 +1812,9 @@ void mtk_dp_check_hdcp_version(struct mtk_dp *mtk_dp, bool only_hdcp1x) if (!only_hdcp1x && dp_tx_hdcp2_support(&mtk_dp->hdcp_info)) return; + if (dp_tx_hdcp1x_support(&mtk_dp->hdcp_info)) + return; + if (tee_add_device(&mtk_dp->hdcp_info, HDCP_NONE) != RET_SUCCESS) mtk_dp->hdcp_info.auth_status = AUTH_FAIL; } @@ -1860,15 +1864,34 @@ static void mtk_dp_hdcp_handle(struct work_struct *data) mtk_dp_check_hdcp_version(mtk_dp, false); if (mtk_dp->hdcp_info.hdcp2_info.enable) dp_tx_hdcp2_set_start_auth(&mtk_dp->hdcp_info, true); + else if (mtk_dp->hdcp_info.hdcp1x_info.enable && + mtk_dp->hdcp_info.hdcp_content_type != DRM_MODE_HDCP_CONTENT_TYPE1) + dp_tx_hdcp1x_set_start_auth(&mtk_dp->hdcp_info, true); else mtk_dp->hdcp_info.auth_status = AUTH_ZERO; } - while (mtk_dp->hdcp_info.hdcp2_info.enable && - mtk_dp->hdcp_info.auth_status != AUTH_FAIL && + while ((mtk_dp->hdcp_info.hdcp1x_info.enable || + mtk_dp->hdcp_info.hdcp2_info.enable) && + mtk_dp->hdcp_info.auth_status != AUTH_FAIL && mtk_dp->hdcp_info.auth_status != AUTH_PASS) { - if (mtk_dp->hdcp_info.hdcp2_info.enable) + if (mtk_dp->hdcp_info.hdcp2_info.enable) { dp_tx_hdcp2_fsm(&mtk_dp->hdcp_info); + if (mtk_dp->hdcp_info.auth_status == AUTH_FAIL) { + tee_remove_device(&mtk_dp->hdcp_info); + mtk_dp_check_hdcp_version(mtk_dp, true); + if (mtk_dp->hdcp_info.hdcp1x_info.enable && + mtk_dp->hdcp_info.hdcp_content_type != + DRM_MODE_HDCP_CONTENT_TYPE1) { + mtk_dp->hdcp_info.hdcp2_info.enable = false; + dp_tx_hdcp1x_set_start_auth(&mtk_dp->hdcp_info, true); + } + } + } + + if (mtk_dp->hdcp_info.hdcp1x_info.enable && + mtk_dp->hdcp_info.hdcp_content_type != DRM_MODE_HDCP_CONTENT_TYPE1) + dp_tx_hdcp1x_fsm(&mtk_dp->hdcp_info); } } @@ -1924,6 +1947,8 @@ static void mtk_dp_hdcp_atomic_check(struct mtk_dp *mtk_dp, struct drm_connector dev_dbg(mtk_dp->dev, "disable HDCP\n"); if (mtk_dp->hdcp_info.hdcp2_info.enable) dp_tx_hdcp2_set_start_auth(&mtk_dp->hdcp_info, false); + else if (mtk_dp->hdcp_info.hdcp1x_info.enable) + dp_tx_hdcp1x_set_start_auth(&mtk_dp->hdcp_info, false); drm_hdcp_update_content_protection(mtk_dp->conn, mtk_dp->hdcp_info.content_protection); @@ -2394,6 +2419,8 @@ static void mtk_dp_bridge_atomic_disable(struct drm_bridge *bridge, if (mtk_dp->hdcp_info.hdcp2_info.enable) dp_tx_hdcp2_set_start_auth(&mtk_dp->hdcp_info, false); + else if (mtk_dp->hdcp_info.hdcp1x_info.enable) + dp_tx_hdcp1x_set_start_auth(&mtk_dp->hdcp_info, false); if (mtk_dp->hdcp_info.content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { mtk_dp->hdcp_info.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; diff --git a/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c new file mode 100644 index 000000000000..33b6cad39714 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019-2024 MediaTek Inc. + */ + +#include "mtk_dp_hdcp1x.h" +#include "mtk_dp_reg.h" +#include "mtk_dp.h" + +static void dp_tx_hdcp1x_start_cipher(struct mtk_hdcp_info *hdcp_info, bool enable) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + + if (enable) { + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, REQ_BLOCK_CIPHER_AUTH, + REQ_BLOCK_CIPHER_AUTH); + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, KM_GENERATED, KM_GENERATED); + } else { + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, 0, KM_GENERATED); + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, 0, REQ_BLOCK_CIPHER_AUTH); + } +} + +static bool dp_tx_hdcp1x_get_r0_available(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + bool R0_available; + u32 ret; + + ret = mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_34A4); + if (ret & BIT(12)) + R0_available = true; + else + R0_available = false; + + return R0_available; +} + +static void dp_tx_hdcp1x_set_repeater(struct mtk_hdcp_info *hdcp_info, bool enable) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + + if (enable) + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4, BIT(15), BIT(15)); + else + mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4, 0, BIT(15)); +} + +void dp_tx_hdcp1x_set_start_auth(struct mtk_hdcp_info *hdcp_info, bool enable) +{ + hdcp_info->hdcp1x_info.enable = enable; + + if (enable) { + hdcp_info->auth_status = AUTH_INIT; + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A0; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_IDLE; + } else { + hdcp_info->auth_status = AUTH_ZERO; + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_H2; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_IDLE; + tee_hdcp_enable_encrypt(hdcp_info, false, HDCP_NONE); + dp_tx_hdcp1x_start_cipher(hdcp_info, false); + tee_hdcp1x_soft_rst(hdcp_info); + } + + hdcp_info->hdcp1x_info.retry_count = 0; +} + +bool dp_tx_hdcp1x_support(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 tmp[2]; + int ret; + + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BCAPS, tmp, 0x1); + + hdcp_info->hdcp1x_info.enable = tmp[0x0] & BIT(0); + hdcp_info->hdcp1x_info.repeater = (tmp[0x0] & BIT(1)) >> 1; + + DPTXHDCPMSG("1.x: CAPABLE: %d, Reapeater: %d\n", + hdcp_info->hdcp1x_info.enable, + hdcp_info->hdcp1x_info.repeater); + + if (!hdcp_info->hdcp1x_info.enable) + return false; + + ret = tee_add_device(hdcp_info, HDCP_VERSION_1X); + if (ret != RET_SUCCESS) { + DPTXHDCPERR("1.x: HDCP TA has some error\n"); + hdcp_info->hdcp1x_info.enable = false; + } + + return hdcp_info->hdcp1x_info.enable; +} + +static bool dp_tx_hdcp1x_init(struct mtk_hdcp_info *hdcp_info) +{ + u8 i; + + hdcp_info->hdcp1x_info.ksv_ready = false; + hdcp_info->hdcp1x_info.r0_read = false; + hdcp_info->hdcp1x_info.b_status = 0x00; + for (i = 0; i < 5; i++) { + hdcp_info->hdcp1x_info.b_ksv[i] = 0x00; + hdcp_info->hdcp1x_info.a_ksv[i] = 0x00; + } + + for (i = 0; i < 5; i++) + hdcp_info->hdcp1x_info.v[i] = 0x00; + + hdcp_info->hdcp1x_info.b_info[0] = 0x00; + hdcp_info->hdcp1x_info.b_info[1] = 0x00; + hdcp_info->hdcp1x_info.max_cascade = false; + hdcp_info->hdcp1x_info.max_devs = false; + hdcp_info->hdcp1x_info.device_count = 0x00; + + tee_hdcp_enable_encrypt(hdcp_info, false, HDCP_NONE); + dp_tx_hdcp1x_start_cipher(hdcp_info, false); + tee_hdcp1x_soft_rst(hdcp_info); + + return true; +} + +static bool dp_tx_hdcp1x_read_sink_b_ksv(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 read_buffer[DRM_HDCP_KSV_LEN], i; + + if (hdcp_info->hdcp1x_info.enable) { + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BKSV, read_buffer, DRM_HDCP_KSV_LEN); + + for (i = 0; i < DRM_HDCP_KSV_LEN; i++) { + hdcp_info->hdcp1x_info.b_ksv[i] = read_buffer[i]; + DPTXHDCPMSG("1.x: Bksv = 0x%x\n", read_buffer[i]); + } + } + + return true; +} + +static bool dp_tx_hdcp1x_check_sink_ksv_ready(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 read_buffer; + + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BSTATUS, &read_buffer, 1); + + hdcp_info->hdcp1x_info.ksv_ready = (read_buffer & BIT(0)) ? true : false; + + return hdcp_info->hdcp1x_info.ksv_ready; +} + +static bool dp_tx_hdcp1x_check_sink_cap(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 read_buffer[0x2]; + + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BCAPS, read_buffer, 1); + + hdcp_info->hdcp1x_info.repeater = (read_buffer[0] & BIT(1)) ? true : false; + + return true; +} + +static bool dp_tx_hdcp1x_read_sink_b_info(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 read_buffer[DRM_HDCP_BSTATUS_LEN]; + + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BINFO, read_buffer, DRM_HDCP_BSTATUS_LEN); + + hdcp_info->hdcp1x_info.b_info[0] = read_buffer[0]; + hdcp_info->hdcp1x_info.b_info[1] = read_buffer[1]; + hdcp_info->hdcp1x_info.max_cascade = (read_buffer[1] & BIT(3)) ? true : false; + hdcp_info->hdcp1x_info.max_devs = (read_buffer[0] & BIT(7)) ? true : false; + hdcp_info->hdcp1x_info.device_count = read_buffer[0] & 0x7F; + + DPTXHDCPMSG("1.x: Binfo max_cascade_EXCEEDED = %d\n", hdcp_info->hdcp1x_info.max_cascade); + DPTXHDCPMSG("1.x: Binfo DEPTH = %d\n", read_buffer[1] & 0x07); + DPTXHDCPMSG("1.x: Binfo max_devs_EXCEEDED = %d\n", hdcp_info->hdcp1x_info.max_devs); + DPTXHDCPMSG("1.x: Binfo device_count = %d\n", hdcp_info->hdcp1x_info.device_count); + return true; +} + +static bool dp_tx_hdcp1x_read_sink_ksv(struct mtk_hdcp_info *hdcp_info, u8 dev_count) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 i; + u8 times = dev_count / 3; + u8 remain = dev_count % 3; + + if (times > 0) { + for (i = 0; i < times; i++) + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_KSV_FIFO, + hdcp_info->hdcp1x_info.ksvfifo + i * 15, 15); + } + + if (remain > 0) + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_KSV_FIFO, + hdcp_info->hdcp1x_info.ksvfifo + times * 15, remain * 5); + + DPTXHDCPMSG("1.x: Read ksvfifo = %x\n", hdcp_info->hdcp1x_info.ksvfifo[0]); + DPTXHDCPMSG("1.x: Read ksvfifo = %x\n", hdcp_info->hdcp1x_info.ksvfifo[1]); + DPTXHDCPMSG("1.x: Read ksvfifo = %x\n", hdcp_info->hdcp1x_info.ksvfifo[2]); + DPTXHDCPMSG("1.x: Read ksvfifo = %x\n", hdcp_info->hdcp1x_info.ksvfifo[3]); + DPTXHDCPMSG("1.x: Read ksvfifo = %x\n", hdcp_info->hdcp1x_info.ksvfifo[4]); + + return true; +} + +static bool dp_tx_hdcp1x_read_sink_sha_v(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 read_buffer[4], i, j; + + for (i = 0; i < 5; i++) { + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_V_PRIME(i), read_buffer, 4); + for (j = 0; j < 4; j++) { + hdcp_info->hdcp1x_info.v[(i * 4) + j] = read_buffer[3 - j]; + DPTXHDCPMSG("1.x: Read sink V = %x\n", + hdcp_info->hdcp1x_info.v[(i * 4) + j]); + } + } + + return true; +} + +static bool dp_tx_hdcp1x_auth_with_repeater(struct mtk_hdcp_info *hdcp_info) +{ + bool ret = false; + u8 *buffer = NULL; + u32 len = 0; + int tmp = 0; + + if (hdcp_info->hdcp1x_info.device_count > HDCP1X_REP_MAXDEVS) { + DPTXHDCPERR("1.x: Repeater: %d DEVs!\n", hdcp_info->hdcp1x_info.device_count); + return false; + } + + dp_tx_hdcp1x_read_sink_ksv(hdcp_info, hdcp_info->hdcp1x_info.device_count); + dp_tx_hdcp1x_read_sink_sha_v(hdcp_info); + + len = hdcp_info->hdcp1x_info.device_count * DRM_HDCP_KSV_LEN + HDCP1X_B_INFO_LEN; + buffer = kmalloc(len, GFP_KERNEL); + if (!buffer) { + DPTXHDCPERR("1.x: Out of Memory\n"); + return false; + } + + memcpy(buffer, hdcp_info->hdcp1x_info.ksvfifo, len - HDCP1X_B_INFO_LEN); + memcpy(buffer + (len - HDCP1X_B_INFO_LEN), hdcp_info->hdcp1x_info.b_info, + HDCP1X_B_INFO_LEN); + tmp = tee_hdcp1x_compute_compare_v(hdcp_info, buffer, len, hdcp_info->hdcp1x_info.v); + if (tmp == RET_COMPARE_PASS) { + DPTXHDCPMSG("1.x: Check V' PASS\n"); + ret = true; + } else { + DPTXHDCPMSG("1.x: Check V' Fail\n"); + } + + kfree(buffer); + return ret; +} + +static bool dp_tx_hdcp1x_verify_b_ksv(struct mtk_hdcp_info *hdcp_info) +{ + int i, j, k = 0; + u8 ksv; + + for (i = 0; i < DRM_HDCP_KSV_LEN; i++) { + ksv = hdcp_info->hdcp1x_info.b_ksv[i]; + for (j = 0; j < 8; j++) + k += (ksv >> j) & 0x01; + } + + if (k != 20) { + DPTXHDCPERR("1.x: Check BKSV 20'1' 20'0' Fail\n"); + return false; + } + + return true; +} + +static bool dp_tx_hdcp1x_write_a_ksv(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 tmp; + int i, k, j; + + tee_get_aksv(hdcp_info, hdcp_info->hdcp1x_info.a_ksv); + drm_dp_dpcd_write(&mtk_dp->aux, DP_AUX_HDCP_AKSV, hdcp_info->hdcp1x_info.a_ksv, + DRM_HDCP_KSV_LEN); + + for (i = 0, k = 0; i < DRM_HDCP_KSV_LEN; i++) { + tmp = hdcp_info->hdcp1x_info.a_ksv[i]; + + for (j = 0; j < 8; j++) + k += (tmp >> j) & 0x01; + DPTXHDCPMSG("1.x: Aksv 0x%x\n", tmp); + } + + if (k != 20) { + DPTXHDCPERR("1.x: Check AKSV 20'1' 20'0' Fail\n"); + return false; + } + + return true; +} + +static void dp_tx_hdcp1x_write_an(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 an_value[DRM_HDCP_AN_LEN] = { /* on DP Spec p99 */ + 0x03, 0x04, 0x07, 0x0C, 0x13, 0x1C, 0x27, 0x34}; + + tee_hdcp1x_set_tx_an(hdcp_info, an_value); + drm_dp_dpcd_write(&mtk_dp->aux, DP_AUX_HDCP_AN, an_value, DRM_HDCP_AN_LEN); + mdelay(5); +} + +static bool dp_tx_hdcp1x_check_r0(struct mtk_hdcp_info *hdcp_info) +{ + struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info); + u8 value[DRM_HDCP_BSTATUS_LEN]; + u8 retry_count = 0; + bool sink_R0_available = false; + bool ret; + int tmp; + + ret = dp_tx_hdcp1x_get_r0_available(hdcp_info); + if (!ret) { + DPTXHDCPERR("1.x: ERR: R0 No Available\n"); + return false; + } + + if (!hdcp_info->hdcp1x_info.r0_read) { + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BSTATUS, value, 1); + sink_R0_available = ((value[0x0] & BIT(1)) == BIT(1)) ? true : false; + + if (!sink_R0_available) { + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BSTATUS, value, 1); + sink_R0_available = ((value[0x0] & BIT(1)) == BIT(1)) ? true : false; + + if (!sink_R0_available) + return false; + } + } + + while (retry_count < 3) { + drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_RI_PRIME, value, DRM_HDCP_RI_LEN); + + tmp = tee_compare_r0(hdcp_info, value, DRM_HDCP_RI_LEN); + if (tmp == RET_COMPARE_PASS) + return true; + + DPTXHDCPMSG("1.x: R0 check FAIL:Rx_R0=0x%x%x\n", value[0x1], value[0x0]); + mdelay(5); + + retry_count++; + } + return false; +} + +static void dp_tx_hdcp1x_state_rst(struct mtk_hdcp_info *hdcp_info) +{ + DPTXHDCPMSG("1.x: Before State Reset:(M : S)= (%d, %d)", + hdcp_info->hdcp1x_info.main_states, + hdcp_info->hdcp1x_info.sub_states); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A0; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_IDLE; +} + +void dp_tx_hdcp1x_fsm(struct mtk_hdcp_info *hdcp_info) +{ + static int pre_main, pre_sub; + static u32 pre_time; + u32 time; + bool ret; + + if (pre_main != hdcp_info->hdcp1x_info.main_states || + hdcp_info->hdcp1x_info.sub_states != pre_sub) { + DPTXHDCPMSG("1.x: State(M : S)= (%d, %d)", + hdcp_info->hdcp1x_info.main_states, + hdcp_info->hdcp1x_info.sub_states); + pre_main = hdcp_info->hdcp1x_info.main_states; + pre_sub = hdcp_info->hdcp1x_info.sub_states; + } + + switch (hdcp_info->hdcp1x_info.main_states) { + case HDCP1X_main_state_H2: + /* HDCP1X_main_state_H2 */ + /* HDCP1X_sub_FSM_auth_fail */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_auth_fail) { + tee_hdcp_enable_encrypt(hdcp_info, false, HDCP_NONE); + DPTXHDCPMSG("1.x: Authentication Fail\n"); + hdcp_info->auth_status = AUTH_FAIL; + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_H2; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_IDLE; + } + break; + + case HDCP1X_main_state_A0: + /* HDCP1X_main_state_A0 */ + /* HDCP1X_sub_FSM_IDLE */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_IDLE) { + if (hdcp_info->hdcp1x_info.retry_count > HDCP1X_REAUNTH_COUNT) { + DPTXHDCPMSG("1.x: Too much retry!\n"); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_H2; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_auth_fail; + break; + } + + dp_tx_hdcp1x_init(hdcp_info); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A0; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_CHECKHDCPCAPABLE; + } + + /* HDCP1X_main_state_A0 */ + /* HDCP1X_sub_FSM_CHECKHDCPCAPABLE */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_CHECKHDCPCAPABLE) { + if (!hdcp_info->hdcp1x_info.enable) { + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + hdcp_info->hdcp1x_info.retry_count++; + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A1; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_exchange_KSV; + } + break; + + case HDCP1X_main_state_A1: + /* HDCP1X_main_state_A1 */ + /* HDCP1X_sub_FSM_exchange_KSV */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_exchange_KSV) { + dp_tx_hdcp1x_write_an(hdcp_info); + ret = dp_tx_hdcp1x_write_a_ksv(hdcp_info); + if (!ret) { + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + pre_time = mtk_dp_get_system_time(); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A1; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_verify_bksv; + } + + /* HDCP1X_main_state_A1 */ + /* HDCP1X_sub_FSM_verify_bksv */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_verify_bksv) { + dp_tx_hdcp1x_read_sink_b_ksv(hdcp_info); + dp_tx_hdcp1x_set_repeater(hdcp_info, hdcp_info->hdcp1x_info.repeater); + + time = mtk_dp_get_time_diff(pre_time); + if (time >= HDCP1X_BSTATUS_TIMEOUT_CNT) { + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + pre_time = mtk_dp_get_system_time(); + ret = dp_tx_hdcp1x_verify_b_ksv(hdcp_info); + if (!ret) { + dp_tx_hdcp1x_state_rst(hdcp_info); + DPTXHDCPMSG("1.x: Invalid BKSV!!\n"); + break; + } + + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A2; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_computation; + } + break; + + case HDCP1X_main_state_A2: + /* HDCP1X_main_state_A2 */ + /* HDCP1X_sub_FSM_computation */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_computation) { + tee_calculate_lm(hdcp_info, hdcp_info->hdcp1x_info.b_ksv); + dp_tx_hdcp1x_start_cipher(hdcp_info, true); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A3; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_check_R0; + pre_time = mtk_dp_get_system_time(); + } + break; + + case HDCP1X_main_state_A3: + /* HDCP1X_main_state_A3 */ + /* HDCP1X_sub_FSM_check_R0 */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_check_R0) { + /* Wait 100ms(at least) before check R0 */ + time = mtk_dp_get_time_diff(pre_time); + if (time < HDCP1X_R0_WDT && !hdcp_info->hdcp1x_info.r0_read) { + mdelay(10); + break; + } + + ret = dp_tx_hdcp1x_check_r0(hdcp_info); + if (!ret) { + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + tee_hdcp_enable_encrypt(hdcp_info, true, HDCP_V1); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A5; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_IDLE; + } + break; + + case HDCP1X_main_state_A4: + /* HDCP1X_main_state_A4 */ + /* HDCP1X_sub_FSM_auth_done */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_auth_done) { + DPTXHDCPMSG("1.x: Authentication done!\n"); + hdcp_info->hdcp1x_info.retry_count = 0; + hdcp_info->auth_status = AUTH_PASS; + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A4; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_IDLE; + + /* unmute */ + } + break; + + case HDCP1X_main_state_A5: + /* HDCP1X_main_state_A5 */ + /* HDCP1X_sub_FSM_IDLE */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_IDLE) { + dp_tx_hdcp1x_check_sink_cap(hdcp_info); + if (!hdcp_info->hdcp1x_info.repeater) { + DPTXHDCPMSG("1.x: No Repeater!\n"); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A4; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_auth_done; + break; + } + + DPTXHDCPMSG("1.x: Repeater!\n"); + pre_time = mtk_dp_get_system_time(); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A6; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_polling_rdy_bit; + } + break; + + case HDCP1X_main_state_A6: + /* HDCP1X_main_state_A6 */ + /* HDCP1X_sub_FSM_polling_rdy_bit */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_polling_rdy_bit) { + time = mtk_dp_get_time_diff(pre_time); + if (time > HDCP1X_REP_RDY_WDT) { + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + time = mtk_dp_get_time_diff(pre_time); + if (!hdcp_info->hdcp1x_info.ksv_ready && time > HDCP1X_REP_RDY_WDT / 2) + dp_tx_hdcp1x_check_sink_ksv_ready(hdcp_info); + + if (hdcp_info->hdcp1x_info.ksv_ready) { + dp_tx_hdcp1x_read_sink_b_info(hdcp_info); + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A7; + hdcp_info->hdcp1x_info.sub_states = + HDCP1X_sub_FSM_auth_with_repeater; + hdcp_info->hdcp1x_info.ksv_ready = false; + } + } + break; + + case HDCP1X_main_state_A7: + /* HDCP1X_main_state_A7 */ + /* HDCP1X_sub_FSM_auth_with_repeater */ + if (hdcp_info->hdcp1x_info.sub_states == HDCP1X_sub_FSM_auth_with_repeater) { + if (hdcp_info->hdcp1x_info.max_cascade || hdcp_info->hdcp1x_info.max_devs) { + DPTXHDCPERR("1.x: MAX CASCADE or MAX DEVS!\n"); + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + ret = dp_tx_hdcp1x_auth_with_repeater(hdcp_info); + if (!ret) { + dp_tx_hdcp1x_state_rst(hdcp_info); + break; + } + + hdcp_info->hdcp1x_info.main_states = HDCP1X_main_state_A4; + hdcp_info->hdcp1x_info.sub_states = HDCP1X_sub_FSM_auth_done; + } + break; + + default: + break; + } +} diff --git a/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h new file mode 100644 index 000000000000..4787c5bd876a --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019-2024 MediaTek Inc. + */ + +#ifndef _MTK_DP_HDCP1X_H_ +#define _MTK_DP_HDCP1X_H_ + +#include "tlc_dp_hdcp.h" + +#define HDCP1X_BSTATUS_TIMEOUT_CNT 600 +#define HDCP1X_R0_WDT 100 +#define HDCP1X_REP_RDY_WDT 5000 + +#define HDCP1X_REAUNTH_COUNT 3 + +enum DPTX_DRV_HDCP1X_main_states { + HDCP1X_main_state_H2 = 0, + HDCP1X_main_state_A0 = 1, + HDCP1X_main_state_A1 = 2, + HDCP1X_main_state_A2 = 3, + HDCP1X_main_state_A3 = 4, + HDCP1X_main_state_A4 = 5, + HDCP1X_main_state_A5 = 6, + HDCP1X_main_state_A6 = 7, + HDCP1X_main_state_A7 = 8, +}; + +enum DPTX_DRV_HDCP1X_sub_states { + HDCP1X_sub_FSM_IDLE = 0, + HDCP1X_sub_FSM_CHECKHDCPCAPABLE = 1, + HDCP1X_sub_FSM_exchange_KSV = 2, + HDCP1X_sub_FSM_verify_bksv = 3, + HDCP1X_sub_FSM_computation = 4, + HDCP1X_sub_FSM_check_R0 = 5, + HDCP1X_sub_FSM_auth_done = 6, + HDCP1X_sub_FSM_polling_rdy_bit = 7, + HDCP1X_sub_FSM_auth_with_repeater = 8, + HDCP1X_sub_FSM_auth_fail = 9, +}; + +bool dp_tx_hdcp1x_support(struct mtk_hdcp_info *hdcp_info); +void dp_tx_hdcp1x_fsm(struct mtk_hdcp_info *hdcp_info); +void dp_tx_hdcp1x_set_start_auth(struct mtk_hdcp_info *hdcp_info, bool enable); + +#endif /* _MTK_DP_HDCP1X_H_ */ diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h index 5cf5059762ed..4481c853c375 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h +++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h @@ -276,6 +276,9 @@ #define MTK_DP_TRANS_P0_3430 0x3430 #define HPD_INT_THD_ECO_DP_TRANS_P0_MASK GENMASK(1, 0) #define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT BIT(1) +#define MTK_DP_TRANS_P0_3480 0x3480 +#define REQ_BLOCK_CIPHER_AUTH BIT(12) +#define KM_GENERATED BIT(4) #define MTK_DP_TRANS_P0_34A4 0x34a4 #define LANE_NUM_DP_TRANS_P0_MASK GENMASK(3, 2) #define MTK_DP_TRANS_P0_34D0 0x34D0 -- 2.43.0