From patchwork Mon Jan 23 18:24:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112732 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1871EC05027 for ; Mon, 23 Jan 2023 18:25:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231951AbjAWSZI (ORCPT ); Mon, 23 Jan 2023 13:25:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35616 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233932AbjAWSY5 (ORCPT ); Mon, 23 Jan 2023 13:24:57 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E68026197; Mon, 23 Jan 2023 10:24:55 -0800 (PST) Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NIISl6011275; Mon, 23 Jan 2023 18:24:49 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=y+RfEs0k8NwyXKD0GxAMIya7VYmGo8VrBVACPQrby80=; b=GXtgvqukS52Hh9XYRSwpveAVylbpDkCtNmShjq55LCRgtC1pzR42KLy3ALMGJtZJXOn4 13q8vw0OERcmTq13WM73NsDJAX2WR477rP2aRaxf2FREYtWSzByaADnxAchW/cN7LcYn /sr29OLy4azqZtOIKOAk8kmMc+Typz99Y8XJtrKF2+qSplSlPyJ0KMV/ofocWQZC7dS9 /Ws+O4x8Bt5M3c+XeoVAeQ2/mvOyjRySP7LQVLhlcE4Fqip4SVxBYGjlgFQ2T27Wq02X FA8Rq0R0ZdPZiFshNODwg+1TcEnEGxDLy6zBP5DxgQIyT8FdHuA9zDuBNVs6GreUr6qF zw== Received: from nalasppmta02.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89frbjqh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:49 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA02.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOlZH032120 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:47 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:47 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability Date: Mon, 23 Jan 2023 10:24:21 -0800 Message-ID: <1674498274-6010-2-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: -eDpfJdhO9VPU8vI9xmsNbUYFChoYIny X-Proofpoint-GUID: -eDpfJdhO9VPU8vI9xmsNbUYFChoYIny X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 lowpriorityscore=0 phishscore=0 malwarescore=0 suspectscore=0 adultscore=0 impostorscore=0 priorityscore=1501 spamscore=0 bulkscore=0 mlxscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230176 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org FEC is pre-requirement of DSC. Therefore FEC has to be enabled before DSC enabled. This patch add functions to read sink's DSC and FEC related DPCD and decode them and set enable flags accordingly. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_panel.c | 91 ++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/dp/dp_panel.h | 20 ++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 1800d89..5078247 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -1,14 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #include "dp_panel.h" +#include #include #include #include +#define DSC_TGT_BPP 8 + struct dp_panel_private { struct device *dev; struct drm_device *drm_dev; @@ -68,6 +72,9 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) goto end; } + print_hex_dump_debug("[drm-dp] SINK DPCD: ", + DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); + link_info->revision = dpcd[DP_DPCD_REV]; major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; @@ -154,6 +161,83 @@ static int dp_panel_update_modes(struct drm_connector *connector, return rc; } +static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel) +{ + if (dp_panel->dsc_dpcd[0]) { + dp_panel->sink_dsc_caps.dsc_capable = true; + dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1]; + dp_panel->sink_dsc_caps.block_pred_en = + dp_panel->dsc_dpcd[6] ? true : false; + dp_panel->sink_dsc_caps.color_depth = + dp_panel->dsc_dpcd[10]; + + if (dp_panel->sink_dsc_caps.version >= 0x11) + dp_panel->dsc_en = true; + } else { + dp_panel->sink_dsc_caps.dsc_capable = false; + dp_panel->dsc_en = false; + } +} + +static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel) +{ + int rlen; + struct dp_panel_private *panel; + int dpcd_rev; + + if (!dp_panel) { + DRM_ERROR("invalid input\n"); + return; + } + + dpcd_rev = dp_panel->dpcd[DP_DPCD_REV]; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + if (dpcd_rev >= 0x14) { + rlen = drm_dp_dpcd_read(panel->aux, DP_DSC_SUPPORT, + dp_panel->dsc_dpcd, (DP_DSC_RECEIVER_CAP_SIZE + 1)); + if (rlen < (DP_DSC_RECEIVER_CAP_SIZE + 1)) { + drm_dbg_dp(panel->drm_dev, "dsc dpcd read failed, rlen=%d\n", rlen); + return; + } + + print_hex_dump_debug("[drm-dp] SINK DSC DPCD: ", + DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen, false); + + dp_panel_decode_dsc_dpcd(dp_panel); + } +} + +static void dp_panel_read_sink_fec_caps(struct dp_panel *dp_panel) +{ + int rlen; + struct dp_panel_private *panel; + s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1); + + if (!dp_panel) { + DRM_ERROR("invalid input\n"); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + rlen = drm_dp_dpcd_readb(panel->aux, DP_FEC_CAPABILITY, + &dp_panel->fec_dpcd); + if (rlen < 1) { + DRM_ERROR("fec capability read failed, rlen=%d\n", rlen); + return; + } + + print_hex_dump_debug("[drm-dp] SINK FEC DPCD: ", + DUMP_PREFIX_NONE, 8, 1, &dp_panel->fec_dpcd, rlen, false); + + dp_panel->fec_en = dp_panel->fec_dpcd & DP_FEC_CAPABLE; + + if (dp_panel->fec_en) + fec_overhead_fp = drm_fixp_from_fraction(100000, 97582); + + dp_panel->fec_overhead_fp = fec_overhead_fp; +} + int dp_panel_read_sink_caps(struct dp_panel *dp_panel, struct drm_connector *connector) { @@ -224,6 +308,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, } panel->aux_cfg_update_done = false; } + + dp_panel_read_sink_fec_caps(dp_panel); + + if (dp_panel->fec_en) + dp_panel_read_sink_dsc_caps(dp_panel); end: return rc; } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index f04d021..fb30b92 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #ifndef _DP_PANEL_H_ @@ -11,6 +12,7 @@ #include "dp_aux.h" #include "dp_link.h" #include "dp_hpd.h" +#include "msm_drv.h" struct edid; @@ -34,12 +36,21 @@ struct dp_panel_in { struct dp_catalog *catalog; }; +struct dp_dsc_caps { + bool dsc_capable; + u8 version; + bool block_pred_en; + u8 color_depth; +}; + struct dp_panel { /* dpcd raw data */ u8 dpcd[DP_RECEIVER_CAP_SIZE + 1]; u8 ds_cap_info[DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE]; u32 ds_port_cnt; u32 dfp_present; + u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE + 1]; + u8 fec_dpcd; struct dp_link_info link_info; struct drm_dp_desc desc; @@ -53,6 +64,13 @@ struct dp_panel { u32 max_dp_link_rate; u32 max_bw_code; + + struct dp_dsc_caps sink_dsc_caps; + bool dsc_feature_enable; + bool fec_feature_enable; + bool dsc_en; + bool fec_en; + s64 fec_overhead_fp; }; int dp_panel_init_panel_info(struct dp_panel *dp_panel); From patchwork Mon Jan 23 18:24:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112733 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DA537C25B50 for ; Mon, 23 Jan 2023 18:25:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233577AbjAWSZM (ORCPT ); Mon, 23 Jan 2023 13:25:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35626 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233935AbjAWSY5 (ORCPT ); Mon, 23 Jan 2023 13:24:57 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 05C791708; Mon, 23 Jan 2023 10:24:57 -0800 (PST) Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NG2lDv009629; Mon, 23 Jan 2023 18:24:51 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=N3olDA1LBSSm/dSW++cUAdhvmNppohlf/LTtX63EUdE=; b=i0/zEvmElgGqvX2M4Sgf732ZwULy2Utu9di1qsKSSG8MUyvAo4wvum7Kuyc1R8AyPyqZ pSS8gFWYl8/LQCGnlJ2eXvG8f49EXnm+AjXO612pmPK7StD2CgzJE+vhtqeAb07Z1sIR KfiZMrqnStGxqY1OJ4Q3yQKBEDWAongSDHyA9yQJpXA+6F8APhXDVeqVMp+2pVpVIuda FMq5Vcti4pGBxFcBgrhrJHsMsymL8Wn8leBFCpThMvipmVr/e+18Osimv4KhUEL/5IMV irq4ryJMAuyuLan2mZ+UbAEzyBjEK+VDnF74CQzzRbs/yiZ7Wq9xzHtBxvDrbSdqhRKl gQ== Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89gt3h91-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:51 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOoYs012288 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:50 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:49 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp Date: Mon, 23 Jan 2023 10:24:22 -0800 Message-ID: <1674498274-6010-3-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: ATIqfrpGjY1s0dZTUFTidqitushnfdWL X-Proofpoint-ORIG-GUID: ATIqfrpGjY1s0dZTUFTidqitushnfdWL X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 spamscore=0 priorityscore=1501 lowpriorityscore=0 bulkscore=0 adultscore=0 clxscore=1015 mlxscore=0 suspectscore=0 phishscore=0 impostorscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org When FEC enabled, it introduces 2.5% overhead into link capacity. This factor have to be considered into calculation supported bpp. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_panel.c | 45 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 5078247..36dad05 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -11,7 +11,7 @@ #include #include -#define DSC_TGT_BPP 8 +#define DSC_TGT_BPP 10 struct dp_panel_private { struct device *dev; @@ -122,20 +122,51 @@ static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, u32 mode_edid_bpp, u32 mode_pclk_khz) { struct dp_link_info *link_info; - const u32 max_supported_bpp = 30, min_supported_bpp = 18; - u32 bpp = 0, data_rate_khz = 0; + struct dp_panel_private *panel; + const u32 max_supported_bpp = 30; + u32 min_supported_bpp = 18; + u32 bpp = 0, link_bitrate = 0, mode_bitrate; + s64 rate_fp = 0; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dp_panel->dsc_en) + min_supported_bpp = 24; bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); link_info = &dp_panel->link_info; - data_rate_khz = link_info->num_lanes * link_info->rate * 8; - while (bpp > min_supported_bpp) { - if (mode_pclk_khz * bpp <= data_rate_khz) + rate_fp = drm_int2fixp(link_info->num_lanes * link_info->rate * 8); + + if (dp_panel->fec_en) + rate_fp = drm_fixp_div(rate_fp, dp_panel->fec_overhead_fp); + + link_bitrate = drm_fixp2int(rate_fp); + + for (; bpp > min_supported_bpp; bpp -= 6) { + if (dp_panel->dsc_en) { + if (bpp == 30 && !(dp_panel->sink_dsc_caps.color_depth & DP_DSC_10_BPC)) + continue; + else if (bpp == 24 && !(dp_panel->sink_dsc_caps.color_depth & DP_DSC_8_BPC)) + continue; + + mode_bitrate = mode_pclk_khz * DSC_TGT_BPP; + } else { + mode_bitrate = mode_pclk_khz * bpp; + } + + if (mode_bitrate <= link_bitrate) break; - bpp -= 6; } + if (bpp < min_supported_bpp) + DRM_ERROR("bpp %d is below minimum supported bpp %d\n", bpp, + min_supported_bpp); + + if (dp_panel->dsc_en && bpp != 24 && bpp != 30 && bpp != 36) + DRM_ERROR("bpp %d is not supported when dsc is enabled\n", bpp); + return bpp; } From patchwork Mon Jan 23 18:24:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112736 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BBE4C61D97 for ; Mon, 23 Jan 2023 18:25:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233598AbjAWSZN (ORCPT ); Mon, 23 Jan 2023 13:25:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233938AbjAWSY7 (ORCPT ); Mon, 23 Jan 2023 13:24:59 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 963401708; Mon, 23 Jan 2023 10:24:58 -0800 (PST) Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NHTZ02001422; Mon, 23 Jan 2023 18:24:53 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=Ji+FAppXotgL8bQEuDA6ylS1qPj07DFCCie3YVYuhB0=; b=SgmSWiSE5d1Im02FsNjUYtcNdN8vxFeB2xTzRb4OHuVCKsicb9B7kuIw5lignW6drkoV qHqS4gO4SkBOI4+NJ7KOrpTcfFdPdLBQyqgJZD4mLpZUtWtrKolA1By4frV7sz5IqYjV NT4jVipxSM5J8iwo7p6gUSoxSCEaHK+ScIGDitDChZDOw182T0oEd8hDPgejeh+Yd5xZ O0gbHU7y5W4WHLuHvZhgq509FXQKS1BUB86zXwSSGSsEmNV/0aDZjMf7G137WLT5NWVU pHp3s4e3wmnV41nlfBU8R2aWuZ2Toj2DM3JIOSPsnSBVDX052dUV4AD1GBZ4ZRGOk3Jj mQ== Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89f5bjw1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:53 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOp26012292 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:51 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:51 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number Date: Mon, 23 Jan 2023 10:24:23 -0800 Message-ID: <1674498274-6010-4-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: 0gKUgY-g8gIjlMS6356gKFQEaaB2kBOL X-Proofpoint-GUID: 0gKUgY-g8gIjlMS6356gKFQEaaB2kBOL X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 bulkscore=0 clxscore=1015 mlxscore=0 spamscore=0 phishscore=0 adultscore=0 lowpriorityscore=0 suspectscore=0 malwarescore=0 priorityscore=1501 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230176 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Mainlink_levels determined when two actions to take place by hardware, a new BS sequence due to start of video and a static HW MVID is sent to panel. This patch add function to configure mainlink level properly base on lane number. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_catalog.c | 37 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/dp/dp_catalog.h | 4 +++- drivers/gpu/drm/msm/dp/dp_ctrl.c | 4 ++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 676279d..7ac37d8 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2021. Qualcomm Innovation Center, Inc. All rights reserved */ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ @@ -359,6 +360,40 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog) ln_mapping); } +void dp_catalog_ctrl_mainlink_levels(struct dp_catalog *dp_catalog, + u8 lane_cnt) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + u32 mainlink_levels, safe_to_exit_level = 14; + + switch (lane_cnt) { + case 1: + safe_to_exit_level = 14; + break; + case 2: + safe_to_exit_level = 8; + break; + case 4: + safe_to_exit_level = 5; + break; + default: + drm_dbg_dp(catalog->drm_dev, "setting the default safe_to_exit_level=%u\n", + safe_to_exit_level); + break; + } + + mainlink_levels = dp_read_link(catalog, REG_DP_MAINLINK_LEVELS); + mainlink_levels &= 0xFE0; + mainlink_levels |= safe_to_exit_level; + + drm_dbg_dp(catalog->drm_dev, "mainlink_level=0x%x, safe_to_exit_level=0x%x\n", + mainlink_levels, safe_to_exit_level); + + dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, mainlink_levels); +} + void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable) { diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 1f717f4..990c162 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2021. Qualcomm Innovation Center, Inc. All rights reserved */ #ifndef _DP_CATALOG_H_ @@ -92,6 +93,7 @@ u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog); void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state); void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config); void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog); +void dp_catalog_ctrl_mainlink_levels(struct dp_catalog *dp_catalog, u8 lane_cnt); void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable); void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb); void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate, diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index dd26ca6..959a78c 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -161,6 +161,8 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl) u32 cc, tb; dp_catalog_ctrl_lane_mapping(ctrl->catalog); + dp_catalog_ctrl_mainlink_levels(ctrl->catalog, + ctrl->link->link_params.num_lanes); dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true); dp_ctrl_config_ctrl(ctrl); @@ -1296,6 +1298,8 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, { int ret = 0; + dp_catalog_ctrl_mainlink_levels(ctrl->catalog, + ctrl->link->link_params.num_lanes); dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true); if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) From patchwork Mon Jan 23 18:24:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112735 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EFB16C54EAA for ; Mon, 23 Jan 2023 18:25:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233568AbjAWSZK (ORCPT ); Mon, 23 Jan 2023 13:25:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233940AbjAWSZB (ORCPT ); Mon, 23 Jan 2023 13:25:01 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0A3371708; Mon, 23 Jan 2023 10:25:01 -0800 (PST) Received: from pps.filterd (m0279864.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NF6C6A009514; Mon, 23 Jan 2023 18:24:54 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=DvToz2ismh6ZXEhHhog2aNFB9JBz0GW54SgHvvHCMmA=; b=WX1kOasc915onD9FPRZOX9HU6970xsAucNUhPffwCpYBwB20SPeuFlE2jgy+8ZE9MpGA 8z5wiAI+YAD1leC2Aef8OKXW+nBwv2QbInZctPnnnt+THmi1Jdh5sUzkc0Xv5QW24k0p dker2tLKa8IEYZ6VFfqqkeUvdpHSDwEO3eiaR2pajsxesyA8FosKv9pefePtEcW1wrwO BSVi1EiEtBdX6gY+5iUJk0dmG4rXLs573Od0kyKWybuAqLw9B9NI3zRIA/oBiKNQS59h Jg7kTdzWjFJ+lAHp4wjKMquRp36O5YomGEX3uQj4nO8X4ePDUJ0KY4V+xearNi7umOnA oQ== Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89dr3hbs-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:54 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA03.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOrWB025827 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:53 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:52 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0 Date: Mon, 23 Jan 2023 10:24:24 -0800 Message-ID: <1674498274-6010-5-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: FDRJnU0GEKSIcLTTyz09TVpomAQzRELe X-Proofpoint-ORIG-GUID: FDRJnU0GEKSIcLTTyz09TVpomAQzRELe X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 clxscore=1015 priorityscore=1501 impostorscore=0 suspectscore=0 spamscore=0 adultscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 malwarescore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org MSA MISC0 bit 1 to 7 contains Colorimetry Indicator Field. At current implementation, Colorimetry Indicator Field of MISC0 is not configured correctly. This patch add support of RGB formats Colorimetry. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 5 +++-- drivers/gpu/drm/msm/dp/dp_link.c | 29 +++++++++++++++++++------ drivers/gpu/drm/msm/dp/dp_panel.c | 45 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/dp/dp_panel.h | 1 + 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 959a78c..d0d1848 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved */ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ @@ -169,7 +170,7 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl) tb = dp_link_get_test_bits_depth(ctrl->link, ctrl->panel->dp_mode.bpp); - cc = dp_link_get_colorimetry_config(ctrl->link); + cc = dp_panel_get_misc_colorimetry_val(ctrl->panel); dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb); dp_panel_timing_cfg(ctrl->panel); } diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index f1f1d64..e957948 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved */ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ @@ -12,6 +13,12 @@ #define DP_TEST_REQUEST_MASK 0x7F +enum dynamic_range { + DP_DYNAMIC_RANGE_RGB_VESA = 0x00, + DP_DYNAMIC_RANGE_RGB_CEA = 0x01, + DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF, +}; + enum audio_sample_rate { AUDIO_SAMPLE_RATE_32_KHZ = 0x00, AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01, @@ -1079,6 +1086,7 @@ int dp_link_process_request(struct dp_link *dp_link) int dp_link_get_colorimetry_config(struct dp_link *dp_link) { u32 cc; + enum dynamic_range dr; struct dp_link_private *link; if (!dp_link) { @@ -1088,14 +1096,21 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link) link = container_of(dp_link, struct dp_link_private, dp_link); - /* - * Unless a video pattern CTS test is ongoing, use RGB_VESA - * Only RGB_VESA and RGB_CEA supported for now - */ + /* unless a video pattern CTS test is ongoing, use CEA_VESA */ if (dp_link_is_video_pattern_requested(link)) - cc = link->dp_link.test_video.test_dyn_range; + dr = link->dp_link.test_video.test_dyn_range; else - cc = DP_TEST_DYNAMIC_RANGE_VESA; + dr = DP_DYNAMIC_RANGE_RGB_VESA; + + /* Only RGB_VESA nd RGB_CEA supported for now */ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_CEA: + cc = BIT(2); + break; + case DP_DYNAMIC_RANGE_RGB_VESA: + default: + cc = 0; + } return cc; } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 36dad05..55bb6b0 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -567,6 +567,51 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel) return 0; } +/** + * Mapper function which outputs colorimetry to be used for a + * given colorspace value when misc field of MSA is used to + * change the colorimetry. Currently only RGB formats have been + * added. This API will be extended to YUV once its supported on DP. + */ +u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel) +{ + u8 colorimetry; + u32 colorspace; + u32 cc; + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + cc = dp_link_get_colorimetry_config(panel->link); + /* + * If there is a non-zero value then compliance test-case + * is going on, otherwise we can honor the colorspace setting + */ + if (cc) + return cc; + + colorspace = dp_panel->connector->state->colorspace; + switch (colorspace) { + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + colorimetry = 0x7; + break; + case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED: + colorimetry = 0x3; + break; + case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT: + colorimetry = 0xb; + break; + case DRM_MODE_COLORIMETRY_OPRGB: + colorimetry = 0xc; + break; + default: + colorimetry = 0; + } + + return colorimetry; +} + struct dp_panel *dp_panel_get(struct dp_panel_in *in) { struct dp_panel_private *panel; diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index fb30b92..1153e88 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -85,6 +85,7 @@ int dp_panel_get_modes(struct dp_panel *dp_panel, struct drm_connector *connector); void dp_panel_handle_sink_request(struct dp_panel *dp_panel); void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable); +u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel); /** * is_link_rate_valid() - validates the link rate From patchwork Mon Jan 23 18:24:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112737 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 933A4C61DA7 for ; Mon, 23 Jan 2023 18:25:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233526AbjAWSZJ (ORCPT ); Mon, 23 Jan 2023 13:25:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232616AbjAWSZG (ORCPT ); Mon, 23 Jan 2023 13:25:06 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BCF31708; Mon, 23 Jan 2023 10:25:03 -0800 (PST) Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NGxWCT017998; Mon, 23 Jan 2023 18:24:56 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=rxwS+37OS6a7JcbXphJwsmVtZaDIJxDvTqcFmkgcupg=; b=cGcb8r1jju2ZffSPszugmSg8rzk8hE366nnVf/9dPwIfMLQ8Gx26E57mu0JFElTgiU7s BMkax1f8ErLPRIoigi0ZQqsfLobgSS5jGnzRnNqsz0qhh6PQGPVTSjZHA1ilVFBcvzzU +f/4jdCSQgGZ7OH3gLBhwpp4cC/tqINf7niVRdLgRK+j5JdAzEzPYcWZ9IWpuIUz37oc DSRTlkhCAy/IIwkMl3oGLIllV93zDKsp1pN3nsIKoPW90AO1IJw6Gm3Kqc3e6SIYxbdH jugnFQKeT/bjDHVx/FteeMLPblVEo3oAjarUsmtAgWZ5LdzMurEy6G8rBJOcTl08FK+g Rg== Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89dnbgx6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:55 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOteH012310 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:55 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:54 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm Date: Mon, 23 Jan 2023 10:24:25 -0800 Message-ID: <1674498274-6010-6-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: 53qVb4YTjLOG9GmfeK6e9Pd-oJF716B5 X-Proofpoint-ORIG-GUID: 53qVb4YTjLOG9GmfeK6e9Pd-oJF716B5 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 clxscore=1015 lowpriorityscore=0 spamscore=0 phishscore=0 mlxscore=0 bulkscore=0 malwarescore=0 mlxlogscore=999 suspectscore=0 priorityscore=1501 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org At display port, the pixel data is packed into TU (transfer units) which is used to carry main video stream data during its horizontal active period. TUs are mapping into the main-Link to facilitate the support of various lane counts regardless of the pixel bit depth and colorimetry format. Stuffing symbols are required if packed data rate less than link symbol rate. TU size is calculated base on factors such as, pixel rate, BPP, main link rate, main link lane and etc, and shall be 32 to 64 link symbols per lane. Each vendor has its own algorithm to calculate TU size. This patch upgrade TU size calculation base on newest algorithm. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 702 +++++++++++++++++++++++---------------- 1 file changed, 416 insertions(+), 286 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index d0d1848..ae9c2b8 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -182,18 +182,24 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl) */ struct tu_algo_data { s64 lclk_fp; + s64 orig_lclk_fp; s64 pclk_fp; + s64 orig_pclk_fp; s64 lwidth; s64 lwidth_fp; + int orig_lwidth; s64 hbp_relative_to_pclk; s64 hbp_relative_to_pclk_fp; int nlanes; + int orig_hbp; int bpp; int pixelEnc; int dsc_en; int async_en; + int fec_en; int bpc; + int rb2; uint delay_start_link_extra_pixclk; int extra_buffer_margin; s64 ratio_fp; @@ -250,19 +256,30 @@ struct tu_algo_data { int even_distribution_BF; int even_distribution_legacy; int even_distribution; + + int hbp_delayStartCheck; + int pre_tu_hw_pipe_delay; + int post_tu_hw_pipe_delay; + int link_config_hactive_time; + int delay_start_link_lclk; + int tu_active_cycles; + s64 parity_symbols; + int resolution_line_time; + int last_partial_lclk; + int min_hblank_violated; s64 delay_start_time_fp; s64 hbp_time_fp; s64 hactive_time_fp; s64 diff_abs_fp; - + int second_loop_set; s64 ratio; }; static int _tu_param_compare(s64 a, s64 b) { - u32 a_sign; - u32 b_sign; + u32 a_int, a_frac, a_sign; + u32 b_int, b_frac, b_sign; s64 a_temp, b_temp, minus_1; if (a == b) @@ -270,8 +287,12 @@ static int _tu_param_compare(s64 a, s64 b) minus_1 = drm_fixp_from_fraction(-1, 1); + a_int = (a >> 32) & 0x7FFFFFFF; + a_frac = a & 0xFFFFFFFF; a_sign = (a >> 32) & 0x80000000 ? 1 : 0; + b_int = (b >> 32) & 0x7FFFFFFF; + b_frac = b & 0xFFFFFFFF; b_sign = (b >> 32) & 0x80000000 ? 1 : 0; if (a_sign > b_sign) @@ -295,6 +316,21 @@ static int _tu_param_compare(s64 a, s64 b) } } +static s64 fixp_subtract(s64 a, s64 b) +{ + s64 minus_1 = drm_fixp_from_fraction(-1, 1); + + if (a >= b) + return a - b; + + return drm_fixp_mul(b - a, minus_1); +} + +static inline int fixp2int_ceil(s64 a) +{ + return a ? drm_fixp2int_ceil(a) : 0; +} + static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, struct tu_algo_data *tu) { @@ -305,6 +341,7 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, s64 pclk_dsc_fp; s64 dwidth_dsc_fp; s64 hbp_dsc_fp; + s64 overhead_dsc; int tot_num_eoc_symbols = 0; int tot_num_hor_bytes = 0; @@ -315,16 +352,22 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, s64 temp1_fp, temp2_fp, temp3_fp; tu->lclk_fp = drm_fixp_from_fraction(in->lclk, 1); + tu->orig_lclk_fp = tu->lclk_fp; tu->pclk_fp = drm_fixp_from_fraction(in->pclk_khz, 1000); + tu->orig_pclk_fp = tu->pclk_fp; tu->lwidth = in->hactive; tu->hbp_relative_to_pclk = in->hporch; tu->nlanes = in->nlanes; tu->bpp = in->bpp; tu->pixelEnc = in->pixel_enc; tu->dsc_en = in->dsc_en; + tu->fec_en = in->fec_en; tu->async_en = in->async_en; tu->lwidth_fp = drm_fixp_from_fraction(in->hactive, 1); + tu->orig_lwidth = in->hactive; tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1); + tu->orig_hbp = in->hporch; + tu->rb2 = (in->hporch <= 80) ? 1 : 0; if (tu->pixelEnc == 420) { temp1_fp = drm_fixp_from_fraction(2, 1); @@ -378,6 +421,7 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, dwidth_dsc_bytes = (tot_num_hor_bytes + tot_num_eoc_symbols + (eoc_bytes == 0 ? 0 : tot_num_dummy_bytes)); + overhead_dsc = dwidth_dsc_bytes / tot_num_hor_bytes; dwidth_dsc_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, 3); @@ -409,12 +453,12 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); - tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp); + tu->new_valid_boundary_link = fixp2int_ceil(temp2_fp); temp = (tu->i_upper_boundary_count * tu->new_valid_boundary_link + tu->i_lower_boundary_count * - (tu->new_valid_boundary_link-1)); + (tu->new_valid_boundary_link - 1)); tu->average_valid2_fp = drm_fixp_from_fraction(temp, (tu->i_upper_boundary_count + tu->i_lower_boundary_count)); @@ -489,11 +533,11 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); - tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp; + tu->n_n_err_fp = fixp_subtract(tu->effective_valid_fp, temp2_fp); temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); - tu->n_err_fp = tu->average_valid2_fp - temp2_fp; + tu->n_err_fp = fixp_subtract(tu->average_valid2_fp, temp2_fp); tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0; @@ -501,11 +545,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) temp2_fp = tu->lwidth_fp; temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); - - if (temp2_fp) - tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp); - else - tu->n_tus_incl_last_incomplete_tu = 0; + tu->n_tus_incl_last_incomplete_tu = fixp2int_ceil(temp2_fp); temp1 = 0; temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); @@ -513,9 +553,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) temp1_fp = tu->average_valid2_fp - temp2_fp; temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1); temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); - - if (temp1_fp) - temp1 = drm_fixp2int_ceil(temp1_fp); + temp1 = fixp2int_ceil(temp1_fp); temp = tu->i_upper_boundary_count * tu->nlanes; temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); @@ -524,32 +562,20 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) temp2_fp = temp1_fp - temp2_fp; temp1_fp = drm_fixp_from_fraction(temp, 1); temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + temp2 = fixp2int_ceil(temp2_fp); - if (temp2_fp) - temp2 = drm_fixp2int_ceil(temp2_fp); - else - temp2 = 0; tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2); temp1_fp = drm_fixp_from_fraction(8, tu->bpp); temp2_fp = drm_fixp_from_fraction( tu->extra_required_bytes_new_tmp, 1); temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); - - if (temp1_fp) - tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp); - else - tu->extra_pclk_cycles_tmp = 0; + tu->extra_pclk_cycles_tmp = fixp2int_ceil(temp1_fp); temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1); temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); - - if (temp1_fp) - tu->extra_pclk_cycles_in_link_clk_tmp = - drm_fixp2int_ceil(temp1_fp); - else - tu->extra_pclk_cycles_in_link_clk_tmp = 0; + tu->extra_pclk_cycles_in_link_clk_tmp = fixp2int_ceil(temp1_fp); tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link; @@ -562,6 +588,57 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1); tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp); + if (tu->rb2) { + temp1_fp = drm_fixp_mul(tu->delay_start_time_fp, tu->lclk_fp); + tu->delay_start_link_lclk = fixp2int_ceil(temp1_fp); + + if (tu->remainder_tus > tu->i_upper_boundary_count) { + temp = (tu->remainder_tus - tu->i_upper_boundary_count) * + (tu->new_valid_boundary_link - 1); + temp += (tu->i_upper_boundary_count * tu->new_valid_boundary_link); + temp *= tu->nlanes; + } else { + temp = tu->nlanes * tu->remainder_tus * tu->new_valid_boundary_link; + } + + temp1 = tu->i_lower_boundary_count * (tu->new_valid_boundary_link - 1); + temp1 += tu->i_upper_boundary_count * tu->new_valid_boundary_link; + temp1 *= tu->paired_tus * tu->nlanes; + temp1_fp = drm_fixp_from_fraction(tu->n_symbols - temp1 - temp, tu->nlanes); + tu->last_partial_lclk = fixp2int_ceil(temp1_fp); + + tu->tu_active_cycles = (int)((tu->n_tus_per_lane * tu->tu_size) + + tu->last_partial_lclk); + tu->post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/; + temp = tu->pre_tu_hw_pipe_delay + tu->delay_start_link_lclk + + tu->tu_active_cycles + tu->post_tu_hw_pipe_delay; + + if (tu->fec_en == 1) { + if (tu->nlanes == 1) { + temp1_fp = drm_fixp_from_fraction(temp, 500); + tu->parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1; + } else { + temp1_fp = drm_fixp_from_fraction(temp, 250); + tu->parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1; + } + } else { //no fec BW impact + tu->parity_symbols = 0; + } + + tu->link_config_hactive_time = temp + tu->parity_symbols; + + if (tu->resolution_line_time >= tu->link_config_hactive_time + 1 /*margin*/) + tu->hbp_delayStartCheck = 1; + else + tu->hbp_delayStartCheck = 0; + } else { + compare_result_3 = _tu_param_compare(tu->hbp_time_fp, tu->delay_start_time_fp); + if (compare_result_3 < 2) + tu->hbp_delayStartCheck = 1; + else + tu->hbp_delayStartCheck = 0; + } + compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp); if (compare_result_1 == 2) compare_result_1 = 1; @@ -574,13 +651,6 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) else compare_result_2 = 0; - compare_result_3 = _tu_param_compare(tu->hbp_time_fp, - tu->delay_start_time_fp); - if (compare_result_3 == 2) - compare_result_3 = 0; - else - compare_result_3 = 1; - if (((tu->even_distribution == 1) || ((tu->even_distribution_BF == 0) && (tu->even_distribution_legacy == 0))) && @@ -588,7 +658,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) compare_result_2 && (compare_result_1 || (tu->min_hblank_violated == 1)) && (tu->new_valid_boundary_link - 1) > 0 && - compare_result_3 && + (tu->hbp_delayStartCheck == 1) && (tu->delay_start_link_tmp <= 1023)) { tu->upper_boundary_count = tu->i_upper_boundary_count; tu->lower_boundary_count = tu->i_lower_boundary_count; @@ -607,342 +677,402 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) } } +static void _dp_calc_boundary(struct tu_algo_data *tu) +{ + s64 temp1_fp = 0, temp2_fp = 0; + + do { + tu->err_fp = drm_fixp_from_fraction(1000, 1); + + temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); + temp2_fp = drm_fixp_from_fraction( + tu->delay_start_link_extra_pixclk, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + tu->extra_buffer_margin = fixp2int_ceil(temp1_fp); + + temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); + temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp); + tu->n_symbols = fixp2int_ceil(temp1_fp); + + for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) { + for (tu->i_upper_boundary_count = 1; + tu->i_upper_boundary_count <= 15; + tu->i_upper_boundary_count++) { + for (tu->i_lower_boundary_count = 1; + tu->i_lower_boundary_count <= 15; + tu->i_lower_boundary_count++) { + _tu_valid_boundary_calc(tu); + } + } + } + tu->delay_start_link_extra_pixclk--; + } while (!tu->boundary_moderation_en && + tu->boundary_mod_lower_err == 1 && + tu->delay_start_link_extra_pixclk != 0 && + ((tu->second_loop_set == 0 && tu->rb2 == 1) || tu->rb2 == 0)); +} + +static void _dp_calc_extra_bytes(struct tu_algo_data *tu) +{ + u64 temp = 0; + s64 temp1_fp = 0, temp2_fp = 0; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); + temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + temp = drm_fixp2int(temp2_fp); + if (temp) + tu->extra_bytes = fixp2int_ceil(temp2_fp); + else + tu->extra_bytes = 0; + + temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1); + temp2_fp = drm_fixp_from_fraction(8, tu->bpp); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + tu->extra_pclk_cycles = fixp2int_ceil(temp1_fp); + + temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); + temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + tu->extra_pclk_cycles_in_link_clk = fixp2int_ceil(temp1_fp); +} + + static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl, struct dp_tu_calc_input *in, struct dp_vc_tu_mapping_table *tu_table) { - struct tu_algo_data *tu; + struct tu_algo_data tu; int compare_result_1, compare_result_2; - u64 temp = 0; + u64 temp = 0, temp1; s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0; s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */ - s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */ - s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */ s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000); u8 DP_BRUTE_FORCE = 1; s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */ uint EXTRA_PIXCLK_CYCLE_DELAY = 4; - uint HBLANK_MARGIN = 4; + s64 HBLANK_MARGIN = drm_fixp_from_fraction(4, 1); + s64 HBLANK_MARGIN_EXTRA = 0; - tu = kzalloc(sizeof(*tu), GFP_KERNEL); - if (!tu) - return; - dp_panel_update_tu_timings(in, tu); + memset(&tu, 0, sizeof(tu)); - tu->err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */ + dp_panel_update_tu_timings(in, &tu); + + tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */ temp1_fp = drm_fixp_from_fraction(4, 1); - temp2_fp = drm_fixp_mul(temp1_fp, tu->lclk_fp); - temp_fp = drm_fixp_div(temp2_fp, tu->pclk_fp); - tu->extra_buffer_margin = drm_fixp2int_ceil(temp_fp); + temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp); + temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp); + tu.extra_buffer_margin = fixp2int_ceil(temp_fp); - temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); - temp2_fp = drm_fixp_mul(tu->pclk_fp, temp1_fp); - temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1); + if (in->compress_ratio == 375 && tu.bpp == 30) + temp1_fp = drm_fixp_from_fraction(24, 8); + else + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + + temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); - tu->ratio_fp = drm_fixp_div(temp2_fp, tu->lclk_fp); - - tu->original_ratio_fp = tu->ratio_fp; - tu->boundary_moderation_en = false; - tu->upper_boundary_count = 0; - tu->lower_boundary_count = 0; - tu->i_upper_boundary_count = 0; - tu->i_lower_boundary_count = 0; - tu->valid_lower_boundary_link = 0; - tu->even_distribution_BF = 0; - tu->even_distribution_legacy = 0; - tu->even_distribution = 0; - tu->delay_start_time_fp = 0; - - tu->err_fp = drm_fixp_from_fraction(1000, 1); - tu->n_err_fp = 0; - tu->n_n_err_fp = 0; - - tu->ratio = drm_fixp2int(tu->ratio_fp); - temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1); - div64_u64_rem(tu->lwidth_fp, temp1_fp, &temp2_fp); - if (temp2_fp != 0 && - !tu->ratio && tu->dsc_en == 0) { - tu->ratio_fp = drm_fixp_mul(tu->ratio_fp, RATIO_SCALE_fp); - tu->ratio = drm_fixp2int(tu->ratio_fp); - if (tu->ratio) - tu->ratio_fp = drm_fixp_from_fraction(1, 1); + tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp); + + tu.original_ratio_fp = tu.ratio_fp; + tu.boundary_moderation_en = false; + tu.upper_boundary_count = 0; + tu.lower_boundary_count = 0; + tu.i_upper_boundary_count = 0; + tu.i_lower_boundary_count = 0; + tu.valid_lower_boundary_link = 0; + tu.even_distribution_BF = 0; + tu.even_distribution_legacy = 0; + tu.even_distribution = 0; + tu.hbp_delayStartCheck = 0; + tu.pre_tu_hw_pipe_delay = 0; + tu.post_tu_hw_pipe_delay = 0; + tu.link_config_hactive_time = 0; + tu.delay_start_link_lclk = 0; + tu.tu_active_cycles = 0; + tu.resolution_line_time = 0; + tu.last_partial_lclk = 0; + tu.delay_start_time_fp = 0; + tu.second_loop_set = 0; + + tu.err_fp = drm_fixp_from_fraction(1000, 1); + tu.n_err_fp = 0; + tu.n_n_err_fp = 0; + + temp = drm_fixp2int(tu.lwidth_fp); + if ((((u32)temp % tu.nlanes) != 0) && (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 2) + && (tu.dsc_en == 0)) { + tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp); + if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1) + tu.ratio_fp = DRM_FIXED_ONE; } - if (tu->ratio > 1) - tu->ratio = 1; + if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1) + tu.ratio_fp = DRM_FIXED_ONE; - if (tu->ratio == 1) - goto tu_size_calc; - - compare_result_1 = _tu_param_compare(tu->ratio_fp, const_p49_fp); - if (!compare_result_1 || compare_result_1 == 1) - compare_result_1 = 1; - else - compare_result_1 = 0; - - compare_result_2 = _tu_param_compare(tu->ratio_fp, const_p56_fp); - if (!compare_result_2 || compare_result_2 == 2) - compare_result_2 = 1; - else - compare_result_2 = 0; - - if (tu->dsc_en && compare_result_1 && compare_result_2) { - HBLANK_MARGIN += 4; - drm_dbg_dp(ctrl->drm_dev, - "increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN); + if (HBLANK_MARGIN_EXTRA != 0) { + HBLANK_MARGIN += HBLANK_MARGIN_EXTRA; + DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN, + HBLANK_MARGIN_EXTRA); } -tu_size_calc: - for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) { - temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); - temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); - temp = drm_fixp2int_ceil(temp2_fp); + for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) { + temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1); + temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + temp = fixp2int_ceil(temp2_fp); temp1_fp = drm_fixp_from_fraction(temp, 1); - tu->n_err_fp = temp1_fp - temp2_fp; + tu.n_err_fp = temp1_fp - temp2_fp; - if (tu->n_err_fp < tu->err_fp) { - tu->err_fp = tu->n_err_fp; - tu->tu_size_desired = tu->tu_size; + if (tu.n_err_fp < tu.err_fp) { + tu.err_fp = tu.n_err_fp; + tu.tu_size_desired = tu.tu_size; } } - tu->tu_size_minus1 = tu->tu_size_desired - 1; + tu.tu_size_minus1 = tu.tu_size_desired - 1; - temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); - temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); - tu->valid_boundary_link = drm_fixp2int_ceil(temp2_fp); + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + tu.valid_boundary_link = fixp2int_ceil(temp2_fp); - temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); - temp2_fp = tu->lwidth_fp; + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = tu.lwidth_fp; temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp); - temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1); + temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1); temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); - tu->n_tus = drm_fixp2int(temp2_fp); + tu.n_tus = drm_fixp2int(temp2_fp); if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000) - tu->n_tus += 1; - - tu->even_distribution_legacy = tu->n_tus % tu->nlanes == 0 ? 1 : 0; - - drm_dbg_dp(ctrl->drm_dev, - "n_sym = %d, num_of_tus = %d\n", - tu->valid_boundary_link, tu->n_tus); - - temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); - temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); - temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1); - temp2_fp = temp1_fp - temp2_fp; - temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1); - temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); - - temp = drm_fixp2int(temp2_fp); - if (temp && temp2_fp) - tu->extra_bytes = drm_fixp2int_ceil(temp2_fp); - else - tu->extra_bytes = 0; - - temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1); - temp2_fp = drm_fixp_from_fraction(8, tu->bpp); - temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + tu.n_tus += 1; - if (temp && temp1_fp) - tu->extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp); - else - tu->extra_pclk_cycles = drm_fixp2int(temp1_fp); + tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0; + DRM_DEBUG("Info: n_sym = %d, num_of_tus = %d\n", + tu.valid_boundary_link, tu.n_tus); - temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); - temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1); - temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + _dp_calc_extra_bytes(&tu); - if (temp1_fp) - tu->extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp); - else - tu->extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp); + tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link; - tu->filler_size = tu->tu_size_desired - tu->valid_boundary_link; + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); - temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); - tu->ratio_by_tu_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); - - tu->delay_start_link = tu->extra_pclk_cycles_in_link_clk + - tu->filler_size + tu->extra_buffer_margin; + tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk + + tu.filler_size + tu.extra_buffer_margin; - tu->resulting_valid_fp = - drm_fixp_from_fraction(tu->valid_boundary_link, 1); + tu.resulting_valid_fp = + drm_fixp_from_fraction(tu.valid_boundary_link, 1); - temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); - temp2_fp = drm_fixp_div(tu->resulting_valid_fp, temp1_fp); - tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp; + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp); + tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; - temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1); - temp1_fp = tu->hbp_relative_to_pclk_fp - temp1_fp; - tu->hbp_time_fp = drm_fixp_div(temp1_fp, tu->pclk_fp); + temp1_fp = drm_fixp_from_fraction((tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1); + tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp); - temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1); - tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp); + temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); + tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); - compare_result_1 = _tu_param_compare(tu->hbp_time_fp, - tu->delay_start_time_fp); - if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */ - tu->min_hblank_violated = 1; + compare_result_1 = _tu_param_compare(tu.hbp_time_fp, + tu.delay_start_time_fp); + if (compare_result_1 == 2) /* hbp_time_fp < delay_start_time_fp */ + tu.min_hblank_violated = 1; - tu->hactive_time_fp = drm_fixp_div(tu->lwidth_fp, tu->pclk_fp); + tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp); - compare_result_2 = _tu_param_compare(tu->hactive_time_fp, - tu->delay_start_time_fp); + compare_result_2 = _tu_param_compare(tu.hactive_time_fp, + tu.delay_start_time_fp); if (compare_result_2 == 2) - tu->min_hblank_violated = 1; - - tu->delay_start_time_fp = 0; + tu.min_hblank_violated = 1; /* brute force */ - tu->delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY; - tu->diff_abs_fp = tu->resulting_valid_fp - tu->ratio_by_tu_fp; + tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY; + tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp; - temp = drm_fixp2int(tu->diff_abs_fp); - if (!temp && tu->diff_abs_fp <= 0xffff) - tu->diff_abs_fp = 0; + temp = drm_fixp2int(tu.diff_abs_fp); + if (!temp && tu.diff_abs_fp <= 0xffff) + tu.diff_abs_fp = 0; /* if(diff_abs < 0) diff_abs *= -1 */ - if (tu->diff_abs_fp < 0) - tu->diff_abs_fp = drm_fixp_mul(tu->diff_abs_fp, -1); + if (tu.diff_abs_fp < 0) + tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1); + + tu.boundary_mod_lower_err = 0; + + temp1_fp = drm_fixp_div(tu.orig_lclk_fp, tu.orig_pclk_fp); + + temp2_fp = drm_fixp_from_fraction(tu.orig_lwidth + tu.orig_hbp, 2); + temp_fp = drm_fixp_mul(temp1_fp, temp2_fp); + tu.resolution_line_time = drm_fixp2int(temp_fp); + tu.pre_tu_hw_pipe_delay = fixp2int_ceil(temp1_fp) + 2 /*cdc fifo write jitter+2*/ + + 3 /*pre-delay start cycles*/ + + 3 /*post-delay start cycles*/ + 1 /*BE on the link*/; + tu.post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/; + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp); + tu.n_symbols = fixp2int_ceil(temp1_fp); + + if (tu.rb2) { + temp1_fp = drm_fixp_mul(tu.delay_start_time_fp, tu.lclk_fp); + tu.delay_start_link_lclk = fixp2int_ceil(temp1_fp); + + tu.new_valid_boundary_link = tu.valid_boundary_link; + tu.i_upper_boundary_count = 1; + tu.i_lower_boundary_count = 0; + + temp1 = tu.i_upper_boundary_count * tu.new_valid_boundary_link; + temp1 += tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1); + tu.average_valid2_fp = drm_fixp_from_fraction(temp1, + (tu.i_upper_boundary_count + tu.i_lower_boundary_count)); + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, tu.average_valid2_fp); + tu.n_tus = drm_fixp2int(temp2_fp); + + tu.n_tus_per_lane = tu.n_tus / tu.nlanes; + tu.paired_tus = (int)((tu.n_tus_per_lane) / + (tu.i_upper_boundary_count + tu.i_lower_boundary_count)); + + tu.remainder_tus = tu.n_tus_per_lane - tu.paired_tus * + (tu.i_upper_boundary_count + tu.i_lower_boundary_count); + + if (tu.remainder_tus > tu.i_upper_boundary_count) { + temp = (tu.remainder_tus - tu.i_upper_boundary_count) * + (tu.new_valid_boundary_link - 1); + temp += (tu.i_upper_boundary_count * tu.new_valid_boundary_link); + temp *= tu.nlanes; + } else { + temp = tu.nlanes * tu.remainder_tus * tu.new_valid_boundary_link; + } - tu->boundary_mod_lower_err = 0; - if ((tu->diff_abs_fp != 0 && - ((tu->diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) || - (tu->even_distribution_legacy == 0) || - (DP_BRUTE_FORCE == 1))) || - (tu->min_hblank_violated == 1)) { - do { - tu->err_fp = drm_fixp_from_fraction(1000, 1); + temp1 = tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1); + temp1 += tu.i_upper_boundary_count * tu.new_valid_boundary_link; + temp1 *= tu.paired_tus * tu.nlanes; + temp1_fp = drm_fixp_from_fraction(tu.n_symbols - temp1 - temp, tu.nlanes); + tu.last_partial_lclk = fixp2int_ceil(temp1_fp); + + tu.tu_active_cycles = (int)((tu.n_tus_per_lane * tu.tu_size) + + tu.last_partial_lclk); + + temp = tu.pre_tu_hw_pipe_delay + tu.delay_start_link_lclk + + tu.tu_active_cycles + tu.post_tu_hw_pipe_delay; + + if (tu.fec_en == 1) { + if (tu.nlanes == 1) { + temp1_fp = drm_fixp_from_fraction(temp, 500); + tu.parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1; + } else { + temp1_fp = drm_fixp_from_fraction(temp, 250); + tu.parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1; + } + } else { //no fec BW impact + tu.parity_symbols = 0; + } - temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); - temp2_fp = drm_fixp_from_fraction( - tu->delay_start_link_extra_pixclk, 1); - temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + tu.link_config_hactive_time = temp + tu.parity_symbols; - if (temp1_fp) - tu->extra_buffer_margin = - drm_fixp2int_ceil(temp1_fp); - else - tu->extra_buffer_margin = 0; + if (tu.link_config_hactive_time + 1 /*margin*/ >= tu.resolution_line_time) + tu.min_hblank_violated = 1; + } - temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); - temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp); + tu.delay_start_time_fp = 0; - if (temp1_fp) - tu->n_symbols = drm_fixp2int_ceil(temp1_fp); - else - tu->n_symbols = 0; - - for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) { - for (tu->i_upper_boundary_count = 1; - tu->i_upper_boundary_count <= 15; - tu->i_upper_boundary_count++) { - for (tu->i_lower_boundary_count = 1; - tu->i_lower_boundary_count <= 15; - tu->i_lower_boundary_count++) { - _tu_valid_boundary_calc(tu); - } - } - } - tu->delay_start_link_extra_pixclk--; - } while (tu->boundary_moderation_en != true && - tu->boundary_mod_lower_err == 1 && - tu->delay_start_link_extra_pixclk != 0); + if ((tu.diff_abs_fp != 0 && + ((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) || + (tu.even_distribution_legacy == 0) || + (DP_BRUTE_FORCE == 1))) || + (tu.min_hblank_violated == 1)) { + _dp_calc_boundary(&tu); - if (tu->boundary_moderation_en == true) { + if (tu.boundary_moderation_en) { temp1_fp = drm_fixp_from_fraction( - (tu->upper_boundary_count * - tu->valid_boundary_link + - tu->lower_boundary_count * - (tu->valid_boundary_link - 1)), 1); + (tu.upper_boundary_count * + tu.valid_boundary_link + + tu.lower_boundary_count * + (tu.valid_boundary_link - 1)), 1); temp2_fp = drm_fixp_from_fraction( - (tu->upper_boundary_count + - tu->lower_boundary_count), 1); - tu->resulting_valid_fp = + (tu.upper_boundary_count + + tu.lower_boundary_count), 1); + tu.resulting_valid_fp = drm_fixp_div(temp1_fp, temp2_fp); temp1_fp = drm_fixp_from_fraction( - tu->tu_size_desired, 1); - tu->ratio_by_tu_fp = - drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + tu.tu_size_desired, 1); + tu.ratio_by_tu_fp = + drm_fixp_mul(tu.original_ratio_fp, temp1_fp); - tu->valid_lower_boundary_link = - tu->valid_boundary_link - 1; + tu.valid_lower_boundary_link = + tu.valid_boundary_link - 1; - temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); - temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp); temp2_fp = drm_fixp_div(temp1_fp, - tu->resulting_valid_fp); - tu->n_tus = drm_fixp2int(temp2_fp); + tu.resulting_valid_fp); + tu.n_tus = drm_fixp2int(temp2_fp); - tu->tu_size_minus1 = tu->tu_size_desired - 1; - tu->even_distribution_BF = 1; + tu.tu_size_minus1 = tu.tu_size_desired - 1; + tu.even_distribution_BF = 1; temp1_fp = - drm_fixp_from_fraction(tu->tu_size_desired, 1); + drm_fixp_from_fraction(tu.tu_size_desired, 1); temp2_fp = - drm_fixp_div(tu->resulting_valid_fp, temp1_fp); - tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp; + drm_fixp_div(tu.resulting_valid_fp, temp1_fp); + tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; } } - temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu->lwidth_fp); + if (tu.async_en) { + temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp); + temp = fixp2int_ceil(temp2_fp); - if (temp2_fp) - temp = drm_fixp2int_ceil(temp2_fp); - else - temp = 0; - - temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1); - temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); - temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); - temp2_fp = drm_fixp_div(temp1_fp, temp2_fp); - temp1_fp = drm_fixp_from_fraction(temp, 1); - temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); - temp = drm_fixp2int(temp2_fp); + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); + temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_div(temp1_fp, temp2_fp); + temp1_fp = drm_fixp_from_fraction(temp, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + temp = drm_fixp2int(temp2_fp); - if (tu->async_en) - tu->delay_start_link += (int)temp; + tu.delay_start_link += (int)temp; + } - temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1); - tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp); + temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); + tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); /* OUTPUTS */ - tu_table->valid_boundary_link = tu->valid_boundary_link; - tu_table->delay_start_link = tu->delay_start_link; - tu_table->boundary_moderation_en = tu->boundary_moderation_en; - tu_table->valid_lower_boundary_link = tu->valid_lower_boundary_link; - tu_table->upper_boundary_count = tu->upper_boundary_count; - tu_table->lower_boundary_count = tu->lower_boundary_count; - tu_table->tu_size_minus1 = tu->tu_size_minus1; - - drm_dbg_dp(ctrl->drm_dev, "TU: valid_boundary_link: %d\n", - tu_table->valid_boundary_link); - drm_dbg_dp(ctrl->drm_dev, "TU: delay_start_link: %d\n", - tu_table->delay_start_link); - drm_dbg_dp(ctrl->drm_dev, "TU: boundary_moderation_en: %d\n", + tu_table->valid_boundary_link = tu.valid_boundary_link; + tu_table->delay_start_link = tu.delay_start_link; + tu_table->boundary_moderation_en = tu.boundary_moderation_en; + tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link; + tu_table->upper_boundary_count = tu.upper_boundary_count; + tu_table->lower_boundary_count = tu.lower_boundary_count; + tu_table->tu_size_minus1 = tu.tu_size_minus1; + + DRM_DEBUG("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link); + DRM_DEBUG("TU: delay_start_link: %d\n", tu_table->delay_start_link); + DRM_DEBUG("TU: boundary_moderation_en: %d\n", tu_table->boundary_moderation_en); - drm_dbg_dp(ctrl->drm_dev, "TU: valid_lower_boundary_link: %d\n", + DRM_DEBUG("TU: valid_lower_boundary_link: %d\n", tu_table->valid_lower_boundary_link); - drm_dbg_dp(ctrl->drm_dev, "TU: upper_boundary_count: %d\n", + DRM_DEBUG("TU: upper_boundary_count: %d\n", tu_table->upper_boundary_count); - drm_dbg_dp(ctrl->drm_dev, "TU: lower_boundary_count: %d\n", + DRM_DEBUG("TU: lower_boundary_count: %d\n", tu_table->lower_boundary_count); - drm_dbg_dp(ctrl->drm_dev, "TU: tu_size_minus1: %d\n", - tu_table->tu_size_minus1); - - kfree(tu); + DRM_DEBUG("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1); } static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, - struct dp_vc_tu_mapping_table *tu_table) + struct dp_vc_tu_mapping_table *tu_table) { struct dp_tu_calc_input in; struct drm_display_mode *drm_mode; From patchwork Mon Jan 23 18:24:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112734 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 46512C61DA4 for ; Mon, 23 Jan 2023 18:25:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233366AbjAWSZJ (ORCPT ); Mon, 23 Jan 2023 13:25:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231741AbjAWSZF (ORCPT ); Mon, 23 Jan 2023 13:25:05 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1230459F7; Mon, 23 Jan 2023 10:25:04 -0800 (PST) Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NF0QeO003107; Mon, 23 Jan 2023 18:24:57 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=bcvdKmtVc7iDNnCIS7zeryMebVqjz0yiH+gCb5bokdA=; b=N9VZSm3lS8bODyILDjWBEz7uBT5wI1eO1hsIEErsOPPI2fImZ4n5J+hHXmloZyeNotRx hsVbqwtmpm3JxiofzJ6XKIS1Unv82zpLhLZiOto491YNk46wmz0ubTzS3w5SFXksYDDW sWXHyXhm+EbLS/ghJRHdj1YQ27ByWAubvjQxSpfuq58BVlav1P2oan6Foa4qv2qWaUSA iDBHBjtiT/4Bvz0n5Il2XG+41vKuPKgyM5hX0LjgstfMD+3DhKvp1FN6zOEEHLYkqClD W/katrEclLQjy18DsrhSbuTdukZVCHJ0xPbT+ZLMsOwPfk9YmYbkyN0b/3qBC5QnhDym 4Q== Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89gt3h9a-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:57 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOuvu012349 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:56 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:56 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 06/14] drm/msm/dp: add display compression related struct Date: Mon, 23 Jan 2023 10:24:26 -0800 Message-ID: <1674498274-6010-7-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: dka5GSLh7yYiey_IoY0wN7Kz24A1m6v- X-Proofpoint-ORIG-GUID: dka5GSLh7yYiey_IoY0wN7Kz24A1m6v- X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 spamscore=0 priorityscore=1501 lowpriorityscore=0 bulkscore=0 adultscore=0 clxscore=1015 mlxscore=0 suspectscore=0 phishscore=0 impostorscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Add display compression related struct to support variant compression mechanism. However, DSC is the only one supported at this moment. VDC may be added later. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_panel.h | 42 ++++++++++++++++++ drivers/gpu/drm/msm/msm_drv.h | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 1153e88..4c45d51 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -21,12 +21,54 @@ struct edid; #define DP_DOWNSTREAM_PORTS 4 #define DP_DOWNSTREAM_CAP_SIZE 4 + +#define DP_PANEL_CAPS_DSC BIT(0) + +enum dp_output_format { + DP_OUTPUT_FORMAT_RGB, + DP_OUTPUT_FORMAT_YCBCR420, + DP_OUTPUT_FORMAT_YCBCR422, + DP_OUTPUT_FORMAT_YCBCR444, + DP_OUTPUT_FORMAT_INVALID, +}; + + +struct dp_panel_info { + u32 h_active; + u32 v_active; + u32 h_back_porch; + u32 h_front_porch; + u32 h_sync_width; + u32 h_active_low; + u32 v_back_porch; + u32 v_front_porch; + u32 v_sync_width; + u32 v_active_low; + u32 h_skew; + u32 refresh_rate; + u32 pixel_clk_khz; + u32 bpp; + bool widebus_en; + struct msm_compression_info comp_info; + s64 dsc_overhead_fp; +}; + struct dp_display_mode { struct drm_display_mode drm_mode; + struct dp_panel_info timing; u32 capabilities; + s64 fec_overhead_fp; + s64 dsc_overhead_fp; u32 bpp; u32 h_active_low; u32 v_active_low; + /** + * @output_format: + * + * This is used to indicate DP output format. + * The output format can be read from drm_mode. + */ + enum dp_output_format output_format; }; struct dp_panel_in { diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 9f0c184..f155803 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved * Copyright (C) 2013 Red Hat * Author: Rob Clark */ @@ -70,6 +71,16 @@ enum msm_dp_controller { #define MAX_H_TILES_PER_DISPLAY 2 /** + * enum msm_display_compression_type - compression method used for pixel stream + * @MSM_DISPLAY_COMPRESSION_NONE: Pixel data is not compressed + * @MSM_DISPLAY_COMPRESSION_DSC: DSC compresison is used + */ +enum msm_display_compression_type { + MSM_DISPLAY_COMPRESSION_NONE, + MSM_DISPLAY_COMPRESSION_DSC, +}; + +/** * enum msm_event_wait - type of HW events to wait for * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel @@ -82,6 +93,84 @@ enum msm_event_wait { }; /** + * struct msm_display_dsc_info - defines dsc configuration + * @config DSC encoder configuration + * @scr_rev: DSC revision. + * @initial_lines: Number of initial lines stored in encoder. + * @pkt_per_line: Number of packets per line. + * @bytes_in_slice: Number of bytes in slice. + * @eol_byte_num: Valid bytes at the end of line. + * @bytes_per_pkt Number of bytes in DSI packet + * @pclk_per_line: Compressed width. + * @slice_last_group_size: Size of last group in pixels. + * @slice_per_pkt: Number of slices per packet. + * @num_active_ss_per_enc: Number of active soft slices per encoder. + * @source_color_space: Source color space of DSC encoder + * @chroma_format: Chroma_format of DSC encoder. + * @det_thresh_flatness: Flatness threshold. + * @extra_width: Extra width required in timing calculations. + * @pps_delay_ms: Post PPS command delay in milliseconds. + * @dsc_4hsmerge_en: Using DSC 4HS merge topology + * @dsc_4hsmerge_padding 4HS merge DSC pair padding value in bytes + * @dsc_4hsmerge_alignment 4HS merge DSC alignment value in bytes + * @half_panel_pu True for single and dual dsc encoders if partial + * update sets the roi width to half of mode width + * False in all other cases + */ +struct msm_display_dsc_info { + struct drm_dsc_config drm_dsc; + u8 scr_rev; + + int initial_lines; + int pkt_per_line; + int bytes_in_slice; + int bytes_per_pkt; + int eol_byte_num; + int pclk_per_line; + int slice_last_group_size; + int slice_per_pkt; + int num_active_ss_per_enc; + int source_color_space; + int chroma_format; + int det_thresh_flatness; + u32 extra_width; + u32 pps_delay_ms; + bool dsc_4hsmerge_en; + u32 dsc_4hsmerge_padding; + u32 dsc_4hsmerge_alignment; + bool half_panel_pu; +}; + +/* + * conver from struct drm_dsc_config to struct msm_display_dsc_info + */ +#define to_msm_dsc_info(dsc) container_of((dsc), struct msm_display_dsc_info, drm_dsc) + +/** + * Bits/pixel target >> 4 (removing the fractional bits) + * returns the integer bpp value from the drm_dsc_config struct + */ +#define DSC_BPP(config) ((config).bits_per_pixel >> 4) + +/** + * struct msm_compression_info - defined panel compression + * @enabled: enabled/disabled + * @comp_type: type of compression supported + * @comp_ratio: compression ratio + * @src_bpp: bits per pixel before compression + * @tgt_bpp: bits per pixel after compression + * @msm_dsc_info: msm dsc info if the compression supported is DSC + */ +struct msm_compression_info { + bool enabled; + enum msm_display_compression_type comp_type; + u32 comp_ratio; + u32 src_bpp; + u32 tgt_bpp; + struct msm_display_dsc_info msm_dsc_info; +}; + +/** * struct msm_display_topology - defines a display topology pipeline * @num_lm: number of layer mixers used * @num_intf: number of interfaces the panel is mounted on From patchwork Mon Jan 23 18:24:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112739 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2CF14C25B50 for ; Mon, 23 Jan 2023 18:25:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231659AbjAWSZR (ORCPT ); Mon, 23 Jan 2023 13:25:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230185AbjAWSZI (ORCPT ); Mon, 23 Jan 2023 13:25:08 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD76A59F7; Mon, 23 Jan 2023 10:25:05 -0800 (PST) Received: from pps.filterd (m0279866.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NFU8Z9002934; Mon, 23 Jan 2023 18:24:59 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=/kECax2Aq2Ou2ddGhZUZw4fOuBh5ZDUL5kOnonadju4=; b=eMFvmlrPmjvENqxCtgjP49U6BYpvlpLYAjGIK7ob3K/Ab1LqxQWo3hR9DuBRXBgTpzZM G23hA/Wt8S6HfbbwEu6/kRVKnUgs9Y81yq6oZQhumGMMnwkJni1lbfTpMvojwfGg3rgf LTVSvNIdDrWRPgR2qb5naU5oCmrbAQd7Aff6md90TYlGMn4hZ7n2+7UHA900+bMQzIQr Dimvd/VvCuko2wp+UcVKk8n0jPG1JMWR3AJWq3ZfYP12mppxuuLHGGH4rWhyJR/svLni 7kVVP09algI0d5Wgj5CkfSSqieyi8tIBpiPCzM36Yg+W4OTd7Tv5SikPf7TlRsFOU9Fo yw== Received: from nalasppmta02.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89hk3hkd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:59 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA02.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIOwp6032205 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:24:58 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:57 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 07/14] drm/msm/dp: add dsc helper functions Date: Mon, 23 Jan 2023 10:24:27 -0800 Message-ID: <1674498274-6010-8-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: DCEm1twCdvWg0JZJKOcvKJDSa2Jog3Rb X-Proofpoint-ORIG-GUID: DCEm1twCdvWg0JZJKOcvKJDSa2Jog3Rb X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 phishscore=0 suspectscore=0 clxscore=1015 mlxscore=0 impostorscore=0 spamscore=0 adultscore=0 bulkscore=0 lowpriorityscore=0 priorityscore=1501 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Add DSC related supporting functions to calculate DSC related parameters. In addition, DSC hardware encoder customized configuration parameters are also included. Algorithms used to perform calculation are derived from system engineer spreadsheet. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c | 537 +++++++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h | 25 ++ drivers/gpu/drm/msm/msm_drv.h | 4 + 4 files changed, 567 insertions(+) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 7274c412..28cf52b 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \ disp/dpu1/dpu_hw_catalog.o \ disp/dpu1/dpu_hw_ctl.o \ disp/dpu1/dpu_hw_dsc.o \ + disp/dpu1/dpu_dsc_helper.o \ disp/dpu1/dpu_hw_interrupts.o \ disp/dpu1/dpu_hw_intf.o \ disp/dpu1/dpu_hw_lm.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c new file mode 100644 index 00000000..48cef23 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c @@ -0,0 +1,537 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2023 The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved + */ + +#include "msm_drv.h" +#include "dpu_kms.h" +#include "dpu_hw_dsc.h" +#include "dpu_dsc_helper.h" + + +#define DPU_DSC_PPS_SIZE 128 + +enum dpu_dsc_ratio_type { + DSC_V11_8BPC_8BPP, + DSC_V11_10BPC_8BPP, + DSC_V11_10BPC_10BPP, + DSC_V11_SCR1_8BPC_8BPP, + DSC_V11_SCR1_10BPC_8BPP, + DSC_V11_SCR1_10BPC_10BPP, + DSC_V12_444_8BPC_8BPP = DSC_V11_SCR1_8BPC_8BPP, + DSC_V12_444_10BPC_8BPP = DSC_V11_SCR1_10BPC_8BPP, + DSC_V12_444_10BPC_10BPP = DSC_V11_SCR1_10BPC_10BPP, + DSC_V12_422_8BPC_7BPP, + DSC_V12_422_8BPC_8BPP, + DSC_V12_422_10BPC_7BPP, + DSC_V12_422_10BPC_10BPP, + DSC_V12_420_8BPC_6BPP, + DSC_V12_420_10BPC_6BPP, + DSC_V12_420_10BPC_7_5BPP, + DSC_RATIO_TYPE_MAX +}; + + +static u16 dpu_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = { + 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, + 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e +}; + +/* + * Rate control - Min QP values for each ratio type in dpu_dsc_ratio_type + */ +static char dpu_dsc_rc_range_min_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { + /* DSC v1.1 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + /* DSC v1.1 SCR and DSC v1.2 RGB 444 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + /* DSC v1.2 YUV422 */ + {0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11}, + {0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + {0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12}, + /* DSC v1.2 YUV420 */ + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10}, + {0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14}, + {0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12}, +}; + +/* + * Rate control - Max QP values for each ratio type in dpu_dsc_ratio_type + */ +static char dpu_dsc_rc_range_max_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { + /* DSC v1.1 */ + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, + {4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + /* DSC v1.1 SCR and DSC v1.2 RGB 444 */ + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, + {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + /* DSC v1.2 YUV422 */ + {3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12}, + {2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + {2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13}, + /* DSC v1.2 YUV420 */ + {2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 12}, + {2, 5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15}, + {2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13}, + }; + +/* + * Rate control - bpg offset values for each ratio type in dpu_dsc_ratio_type + */ +static char dpu_dsc_rc_range_bpg[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = { + /* DSC v1.1 */ + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12}, + /* DSC v1.1 SCR and DSC V1.2 RGB 444 */ + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12}, + /* DSC v1.2 YUV422 */ + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12}, + {10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12}, + /* DSC v1.2 YUV420 */ + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12}, + {10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12}, +}; + +static struct dpu_dsc_rc_init_params_lut { + u32 rc_quant_incr_limit0; + u32 rc_quant_incr_limit1; + u32 initial_fullness_offset; + u32 initial_xmit_delay; + u32 second_line_bpg_offset; + u32 second_line_offset_adj; + u32 flatness_min_qp; + u32 flatness_max_qp; +} dpu_dsc_rc_init_param_lut[] = { + /* DSC v1.1 */ + {11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V11_8BPC_8BPP */ + {15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V11_10BPC_8BPP */ + {15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V11_10BPC_10BPP */ + /* DSC v1.1 SCR and DSC v1.2 RGB 444 */ + {11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V12_444_8BPC_8BPP or DSC_V11_SCR1_8BPC_8BPP */ + {15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_8BPP or DSC_V11_SCR1_10BPC_8BPP */ + {15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_10BPP or DSC_V11_SCR1_10BPC_10BPP */ + /* DSC v1.2 YUV422 */ + {11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */ + {11, 11, 2048, 341, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_8BPP */ + {15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_7BPP */ + {15, 15, 2048, 273, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_10BPP */ + /* DSC v1.2 YUV420 */ + {11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */ + {11, 11, 2048, 341, 12, 512, 3, 12}, /* DSC_V12_420_8BPC_6BPP */ + {15, 15, 2048, 341, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_6BPP */ + {15, 15, 2048, 256, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_7_5BPP */ +}; + +/** + * Maps to lookup the dpu_dsc_ratio_type index used in rate control tables + */ +static struct dpu_dsc_table_index_lut { + u32 fmt; + u32 scr_ver; + u32 minor_ver; + u32 bpc; + u32 bpp; + u32 type; +} dpu_dsc_index_map[] = { + /* DSC 1.1 formats - scr version is considered */ + {MSM_CHROMA_444, 0, 1, 8, 8, DSC_V11_8BPC_8BPP}, + {MSM_CHROMA_444, 0, 1, 10, 8, DSC_V11_10BPC_8BPP}, + {MSM_CHROMA_444, 0, 1, 10, 10, DSC_V11_10BPC_10BPP}, + + {MSM_CHROMA_444, 1, 1, 8, 8, DSC_V11_SCR1_8BPC_8BPP}, + {MSM_CHROMA_444, 1, 1, 10, 8, DSC_V11_SCR1_10BPC_8BPP}, + {MSM_CHROMA_444, 1, 1, 10, 10, DSC_V11_SCR1_10BPC_10BPP}, + + /* DSC 1.2 formats - scr version is no-op */ + {MSM_CHROMA_444, -1, 2, 8, 8, DSC_V12_444_8BPC_8BPP}, + {MSM_CHROMA_444, -1, 2, 10, 8, DSC_V12_444_10BPC_8BPP}, + {MSM_CHROMA_444, -1, 2, 10, 10, DSC_V12_444_10BPC_10BPP}, + + {MSM_CHROMA_422, -1, 2, 8, 7, DSC_V12_422_8BPC_7BPP}, + {MSM_CHROMA_422, -1, 2, 8, 8, DSC_V12_422_8BPC_8BPP}, + {MSM_CHROMA_422, -1, 2, 10, 7, DSC_V12_422_10BPC_7BPP}, + {MSM_CHROMA_422, -1, 2, 10, 10, DSC_V12_422_10BPC_10BPP}, + + {MSM_CHROMA_420, -1, 2, 8, 6, DSC_V12_420_8BPC_6BPP}, + {MSM_CHROMA_420, -1, 2, 10, 6, DSC_V12_420_10BPC_6BPP}, +}; + +static int _get_rc_table_index(struct drm_dsc_config *dsc, int scr_ver) +{ + u32 bpp, bpc, i, fmt = MSM_CHROMA_444; + + if (dsc->dsc_version_major != 0x1) { + DPU_ERROR("unsupported major version %d\n", + dsc->dsc_version_major); + return -EINVAL; + } + + bpc = dsc->bits_per_component; + bpp = DSC_BPP(*dsc); + + if (dsc->native_422) + fmt = MSM_CHROMA_422; + else if (dsc->native_420) + fmt = MSM_CHROMA_420; + + + for (i = 0; i < ARRAY_SIZE(dpu_dsc_index_map); i++) { + if (dsc->dsc_version_minor == dpu_dsc_index_map[i].minor_ver && + fmt == dpu_dsc_index_map[i].fmt && + bpc == dpu_dsc_index_map[i].bpc && + bpp == dpu_dsc_index_map[i].bpp && + (dsc->dsc_version_minor != 0x1 || + scr_ver == dpu_dsc_index_map[i].scr_ver)) + return dpu_dsc_index_map[i].type; + } + + DPU_ERROR("unsupported DSC v%d.%dr%d, bpc:%d, bpp:%d, fmt:0x%x\n", + dsc->dsc_version_major, dsc->dsc_version_minor, + scr_ver, bpc, bpp, fmt); + return -EINVAL; +} + +u8 _get_dsc_v1_2_bpg_offset(struct drm_dsc_config *dsc) +{ + u8 bpg_offset = 0; + u8 uncompressed_bpg_rate; + u8 bpp = DSC_BPP(*dsc); + + if (dsc->slice_height < 8) + bpg_offset = 2 * (dsc->slice_height - 1); + else if (dsc->slice_height < 20) + bpg_offset = 12; + else if (dsc->slice_height <= 30) + bpg_offset = 13; + else if (dsc->slice_height < 42) + bpg_offset = 14; + else + bpg_offset = 15; + + if (dsc->native_422) + uncompressed_bpg_rate = 3 * bpp * 4; + else if (dsc->native_420) + uncompressed_bpg_rate = 3 * bpp; + else + uncompressed_bpg_rate = (3 * bpp + 2) * 3; + + if (bpg_offset < (uncompressed_bpg_rate - (3 * bpp))) + return bpg_offset; + else + return (uncompressed_bpg_rate - (3 * bpp)); +} + +int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver) +{ + int bpp, bpc; + int groups_per_line, groups_total; + int min_rate_buffer_size; + int hrd_delay; + int pre_num_extra_mux_bits, num_extra_mux_bits; + int slice_bits; + int data; + int final_value, final_scale; + struct dpu_dsc_rc_init_params_lut *rc_param_lut; + u32 slice_width_mod; + int i, ratio_idx; + + dsc->rc_model_size = 8192; + + if ((dsc->dsc_version_major == 0x1) && + (dsc->dsc_version_minor == 0x1)) { + if (scr_ver == 0x1) + dsc->first_line_bpg_offset = 15; + else + dsc->first_line_bpg_offset = 12; + } else if (dsc->dsc_version_minor == 0x2) { + dsc->first_line_bpg_offset = _get_dsc_v1_2_bpg_offset(dsc); + } + + dsc->rc_edge_factor = 6; + dsc->rc_tgt_offset_high = 3; + dsc->rc_tgt_offset_low = 3; + dsc->simple_422 = 0; + dsc->convert_rgb = !(dsc->native_422 | dsc->native_420); + dsc->vbr_enable = 0; + + bpp = DSC_BPP(*dsc); + bpc = dsc->bits_per_component; + + ratio_idx = _get_rc_table_index(dsc, scr_ver); + if ((ratio_idx < 0) || (ratio_idx >= DSC_RATIO_TYPE_MAX)) + return -EINVAL; + + + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) + dsc->rc_buf_thresh[i] = dpu_dsc_rc_buf_thresh[i]; + + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + dsc->rc_range_params[i].range_min_qp = + dpu_dsc_rc_range_min_qp[ratio_idx][i]; + dsc->rc_range_params[i].range_max_qp = + dpu_dsc_rc_range_max_qp[ratio_idx][i]; + dsc->rc_range_params[i].range_bpg_offset = + dpu_dsc_rc_range_bpg[ratio_idx][i]; + } + + rc_param_lut = &dpu_dsc_rc_init_param_lut[ratio_idx]; + dsc->rc_quant_incr_limit0 = rc_param_lut->rc_quant_incr_limit0; + dsc->rc_quant_incr_limit1 = rc_param_lut->rc_quant_incr_limit1; + dsc->initial_offset = rc_param_lut->initial_fullness_offset; + dsc->initial_xmit_delay = rc_param_lut->initial_xmit_delay; + dsc->second_line_bpg_offset = rc_param_lut->second_line_bpg_offset; + dsc->second_line_offset_adj = rc_param_lut->second_line_offset_adj; + dsc->flatness_min_qp = rc_param_lut->flatness_min_qp; + dsc->flatness_max_qp = rc_param_lut->flatness_max_qp; + + slice_width_mod = dsc->slice_width; + if (dsc->native_422 || dsc->native_420) { + slice_width_mod = dsc->slice_width / 2; + bpp = bpp * 2; + } + + dsc->line_buf_depth = bpc + 1; + dsc->mux_word_size = bpc > 10 ? DSC_MUX_WORD_SIZE_12_BPC : DSC_MUX_WORD_SIZE_8_10_BPC; + + if ((dsc->dsc_version_minor == 0x2) && (dsc->native_420)) + dsc->nsl_bpg_offset = (2048 * (DIV_ROUND_UP(dsc->second_line_bpg_offset, + (dsc->slice_height - 1)))); + + groups_per_line = DIV_ROUND_UP(slice_width_mod, 3); + + dsc->slice_chunk_size = slice_width_mod * bpp / 8; + if ((slice_width_mod * bpp) % 8) + dsc->slice_chunk_size++; + + /* rbs-min */ + min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + + dsc->initial_xmit_delay * bpp + + groups_per_line * dsc->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); + + dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; + + dsc->initial_scale_value = 8 * dsc->rc_model_size / + (dsc->rc_model_size - dsc->initial_offset); + + slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height; + + groups_total = groups_per_line * dsc->slice_height; + + data = dsc->first_line_bpg_offset * 2048; + + dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); + + if (dsc->native_422) + pre_num_extra_mux_bits = 4 * dsc->mux_word_size + (4 * bpc + 4) + (3 * 4 * bpc) - 2; + else if (dsc->native_420) + pre_num_extra_mux_bits = 3 * dsc->mux_word_size + (4 * bpc + 4) + (2 * 4 * bpc) - 2; + else + pre_num_extra_mux_bits = 3 * (dsc->mux_word_size + (4 * bpc + 4) - 2); + + num_extra_mux_bits = pre_num_extra_mux_bits - (dsc->mux_word_size - + ((slice_bits - pre_num_extra_mux_bits) % dsc->mux_word_size)); + + data = 2048 * (dsc->rc_model_size - dsc->initial_offset + + num_extra_mux_bits); + dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); + + data = dsc->initial_xmit_delay * bpp; + final_value = dsc->rc_model_size - data + num_extra_mux_bits; + + final_scale = 8 * dsc->rc_model_size / + (dsc->rc_model_size - final_value); + + dsc->final_offset = final_value; + + data = (final_scale - 9) * (dsc->nfl_bpg_offset + + dsc->slice_bpg_offset); + dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; + + dsc->scale_decrement_interval = groups_per_line / + (dsc->initial_scale_value - 8); + + return 0; +} + +bool dpu_dsc_ich_reset_override_needed(bool pu_en, + struct msm_display_dsc_info *dsc_info) +{ + /* + * As per the DSC spec, ICH_RESET can be either end of the slice line + * or at the end of the slice. HW internally generates ich_reset at + * end of the slice line if DSC_MERGE is used or encoder has two + * soft slices. However, if encoder has only 1 soft slice and DSC_MERGE + * is not used then it will generate ich_reset at the end of slice. + * + * Now as per the spec, during one PPS session, position where + * ich_reset is generated should not change. Now if full-screen frame + * has more than 1 soft slice then HW will automatically generate + * ich_reset at the end of slice_line. But for the same panel, if + * partial frame is enabled and only 1 encoder is used with 1 slice, + * then HW will generate ich_reset at end of the slice. This is a + * mismatch. Prevent this by overriding HW's decision. + */ + return pu_en && dsc_info && (dsc_info->drm_dsc.slice_count > 1) && + (dsc_info->drm_dsc.slice_width == dsc_info->drm_dsc.pic_width); +} + +int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc_info, + int enc_ip_width, int dsc_cmn_mode) +{ + int max_ssm_delay, max_se_size, max_muxword_size; + int compress_bpp_group, obuf_latency, input_ssm_out_latency; + int base_hs_latency, chunk_bits, ob_data_width; + int output_rate_extra_budget_bits, multi_hs_extra_budget_bits; + int multi_hs_extra_latency, mux_word_size; + int ob_data_width_4comps, ob_data_width_3comps; + int output_rate_ratio_complement, container_slice_width; + int rtl_num_components, multi_hs_c, multi_hs_d; + + int bpc = dsc_info->drm_dsc.bits_per_component; + int bpp = DSC_BPP(dsc_info->drm_dsc); + bool native_422 = dsc_info->drm_dsc.native_422; + bool native_420 = dsc_info->drm_dsc.native_420; + + /* Hardent core config */ + int multiplex_mode_enable = 0, split_panel_enable = 0; + int rtl_max_bpc = 10, rtl_output_data_width = 64; + int pipeline_latency = 28; + + if (dsc_cmn_mode & DSC_MODE_MULTIPLEX) + multiplex_mode_enable = 1; + if (dsc_cmn_mode & DSC_MODE_SPLIT_PANEL) + split_panel_enable = 1; + container_slice_width = (native_422 ? + dsc_info->drm_dsc.slice_width / 2 : dsc_info->drm_dsc.slice_width); + max_muxword_size = (rtl_max_bpc >= 12) ? 64 : 48; + max_se_size = 4 * (rtl_max_bpc + 1); + max_ssm_delay = max_se_size + max_muxword_size - 1; + mux_word_size = (bpc >= 12) ? 64 : 48; + compress_bpp_group = native_422 ? (2 * bpp) : bpp; + input_ssm_out_latency = pipeline_latency + 3 * (max_ssm_delay + 2) + * dsc_info->num_active_ss_per_enc; + rtl_num_components = (native_420 || native_422) ? 4 : 3; + ob_data_width_4comps = (rtl_output_data_width >= (2 * + max_muxword_size)) ? + rtl_output_data_width : + (2 * rtl_output_data_width); + ob_data_width_3comps = (rtl_output_data_width >= max_muxword_size) ? + rtl_output_data_width : 2 * rtl_output_data_width; + ob_data_width = (rtl_num_components == 4) ? + ob_data_width_4comps : ob_data_width_3comps; + obuf_latency = DIV_ROUND_UP((9 * ob_data_width + mux_word_size), + compress_bpp_group) + 1; + base_hs_latency = dsc_info->drm_dsc.initial_xmit_delay + + input_ssm_out_latency + obuf_latency; + chunk_bits = 8 * dsc_info->drm_dsc.slice_chunk_size; + output_rate_ratio_complement = ob_data_width - compress_bpp_group; + output_rate_extra_budget_bits = + (output_rate_ratio_complement * chunk_bits) >> + ((ob_data_width == 128) ? 7 : 6); + multi_hs_c = split_panel_enable * multiplex_mode_enable; + multi_hs_d = (dsc_info->num_active_ss_per_enc > 1) * (ob_data_width > compress_bpp_group); + multi_hs_extra_budget_bits = multi_hs_c ? + chunk_bits : (multi_hs_d ? chunk_bits : + output_rate_extra_budget_bits); + multi_hs_extra_latency = DIV_ROUND_UP(multi_hs_extra_budget_bits, + compress_bpp_group); + dsc_info->initial_lines = DIV_ROUND_UP((base_hs_latency + + multi_hs_extra_latency), + container_slice_width); + + return 0; +} + +int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info, + int intf_width) +{ + int mod_offset; + int slice_per_pkt, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + u16 bpp; + u32 bytes_in_dsc_pair; + u32 total_bytes_in_dsc_pair; + + if (!dsc_info || !dsc_info->drm_dsc.slice_width || + !dsc_info->drm_dsc.slice_height || + intf_width < dsc_info->drm_dsc.slice_width) { + DPU_ERROR("invalid input, intf_width=%d slice_width=%d\n", + intf_width, dsc_info ? dsc_info->drm_dsc.slice_width : + -1); + return -EINVAL; + } + + mod_offset = dsc_info->drm_dsc.slice_width % 3; + + + switch (mod_offset) { + case 0: + dsc_info->slice_last_group_size = 2; + break; + case 1: + dsc_info->slice_last_group_size = 0; + break; + case 2: + dsc_info->slice_last_group_size = 1; + break; + default: + break; + } + + dsc_info->det_thresh_flatness = + 2 << (dsc_info->drm_dsc.bits_per_component - 8); + + slice_per_pkt = dsc_info->slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, + dsc_info->drm_dsc.slice_width); + + + /* + * If slice_per_pkt is greater than slice_per_intf then default to 1. + * This can happen during partial update. + */ + if (slice_per_pkt > slice_per_intf) + slice_per_pkt = 1; + + bpp = DSC_BPP(dsc_info->drm_dsc); + bytes_in_slice = DIV_ROUND_UP(dsc_info->drm_dsc.slice_width * bpp, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + + dsc_info->eol_byte_num = total_bytes_per_intf % 3; + dsc_info->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc_info->bytes_in_slice = bytes_in_slice; + dsc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt; + dsc_info->pkt_per_line = slice_per_intf / slice_per_pkt; + + + bytes_in_dsc_pair = DIV_ROUND_UP(bytes_in_slice * 2, 3); + if (bytes_in_dsc_pair % 8) { + dsc_info->dsc_4hsmerge_padding = 8 - (bytes_in_dsc_pair % 8); + total_bytes_in_dsc_pair = bytes_in_dsc_pair + + dsc_info->dsc_4hsmerge_padding; + if (total_bytes_in_dsc_pair % 16) + dsc_info->dsc_4hsmerge_alignment = 16 - + (total_bytes_in_dsc_pair % 16); + } + + return 0; +} + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h new file mode 100644 index 00000000..9f26455 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 - 2023 The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved + */ + +#ifndef __DPU_DSC_HELPER_H__ +#define __DPU_DSC_HELPER_H__ + +#include "msm_drv.h" + +#define DSC_1_1_PPS_PARAMETER_SET_ELEMENTS 88 + +int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver); + +int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info, + int intf_width); + +bool dpu_dsc_ich_reset_override_needed(bool pu_en, struct msm_display_dsc_info *dsc); + +int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, + int enc_ip_width, int dsc_cmn_mode); + +#endif /* __DPU_DSC_HELPER_H__ */ + diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index f155803..cf4eb8d 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -57,6 +57,10 @@ struct msm_disp_state; #define MAX_CRTCS 8 #define MAX_BRIDGES 8 +#define MSM_CHROMA_444 0x0 +#define MSM_CHROMA_422 0x1 +#define MSM_CHROMA_420 0x2 + #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) enum msm_dp_controller { From patchwork Mon Jan 23 18:24:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112742 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8FA7BC54EAA for ; Mon, 23 Jan 2023 18:25:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233789AbjAWSZw (ORCPT ); Mon, 23 Jan 2023 13:25:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37478 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233753AbjAWSZs (ORCPT ); Mon, 23 Jan 2023 13:25:48 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC81C31E1B; Mon, 23 Jan 2023 10:25:09 -0800 (PST) Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NIB8ou010617; Mon, 23 Jan 2023 18:25:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=nwdEX0oFMN+arr+NrzSEbEVp3yG7g0eC18ghM7sVN8Y=; b=UeMF7tEaMEYD++YhYIwyfsHj7x/R6pRFgrXruMHI2ctQwZTOLL/7G63D86BpwtYM5FUP hN+3gkpGzO9UkYTT6Fd/clIAlM9mV9wJ/ckTZ88YRwAQNjGSCefRmkbYLhtkQ/YVYzdR PrZVBfIguWMeDGTT1gs6/N5h6teQck/DFvhms0H31To4a36z6KUsVdOoX3AOsVki9NuN Ywr6atyIPz1vRS7k/gdYhMqdbS9WeI4v4S8jvcfBaUstECls+NtnUOU/F4c166EoKtd+ uOk3VbtlL6o+iWtPPaYYnXuvHslYrCvv82z5ErBCjN+ldh5UHxBiEoFueInhL2+JbKx3 Hw== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89fm3jxf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:01 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIP0pc003486 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:00 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:24:59 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller Date: Mon, 23 Jan 2023 10:24:28 -0800 Message-ID: <1674498274-6010-9-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: obWXNA70JxROHw85hZU52dBoMRF0UOER X-Proofpoint-GUID: obWXNA70JxROHw85hZU52dBoMRF0UOER X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 clxscore=1015 malwarescore=0 bulkscore=0 phishscore=0 lowpriorityscore=0 mlxlogscore=999 mlxscore=0 priorityscore=1501 adultscore=0 suspectscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230176 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch provides DSC required functions at DP controller to complete DSC feature. those functions include enable fec, configure dsc, configure dto, transmit pps and finally flush hardware registers. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/dp/dp_catalog.c | 139 ++++++++- drivers/gpu/drm/msm/dp/dp_catalog.h | 93 ++++++ drivers/gpu/drm/msm/dp/dp_ctrl.c | 132 ++++++++- drivers/gpu/drm/msm/dp/dp_display.c | 61 +++- drivers/gpu/drm/msm/dp/dp_panel.c | 570 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/dp/dp_panel.h | 4 + drivers/gpu/drm/msm/dp/dp_reg.h | 40 ++- drivers/gpu/drm/msm/msm_drv.h | 16 + 8 files changed, 1033 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 7ac37d8..20a86e7 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -48,6 +48,11 @@ #define DP_INTERRUPT_STATUS2_MASK \ (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT) +enum dp_flush_bit { + DP_PPS_FLUSH, + DP_DHDR_FLUSH, +}; + struct dp_catalog_private { struct device *dev; struct drm_device *drm_dev; @@ -277,6 +282,30 @@ static void dump_regs(void __iomem *base, int len) } } +void dp_catalog_fec_config(struct dp_catalog *dp_catalog, bool enable) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 reg; + + reg = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + + /* + * fec_en = BIT(12) + * fec_seq_mode = BIT(22) + * sde_flush = BIT(23) | BIT(24) + * fb_boundary_sel = BIT(25) + */ + if (enable) + reg |= BIT(12) | BIT(22) | BIT(23) | BIT(24) | BIT(25); + else + reg &= ~BIT(12); + + dp_write_link(catalog, REG_DP_MAINLINK_CTRL, reg); + /* make sure mainlink configuration is updated with fec sequence */ + wmb(); +} + void dp_catalog_dump_regs(struct dp_catalog *dp_catalog) { struct dp_catalog_private *catalog = container_of(dp_catalog, @@ -344,6 +373,54 @@ void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 cfg) dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg); } +void dp_catalog_config_dsc_dto(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data; + u32 reg; + + dp_write_p0(catalog, MMSS_DP_DSC_DTO_COUNT, dsc_data->dto_count); + + reg = dp_read_p0(catalog, MMSS_DP_DSC_DTO); + + if (dsc_data->dto_en) { + reg |= BIT(0); + reg |= BIT(3); + reg |= (dsc_data->dto_n << 8); + reg |= (dsc_data->dto_d << 16); + } + + dp_write_p0(catalog, MMSS_DP_DSC_DTO, reg); + + reg = 0; + if (dsc_data->dsc_en) { + reg = BIT(0); + reg |= (dsc_data->eol_byte_num << 3); + reg |= (dsc_data->slice_per_pkt << 5); + reg |= (dsc_data->bytes_per_pkt << 16); + reg |= (dsc_data->be_in_lane << 10); + } + dp_write_link(catalog, DP_COMPRESSION_MODE_CTRL, reg); + + drm_dbg_dp(catalog->drm_dev, "compression:0x%x\n", reg); +} + +void dp_catalog_override_ack_dto(struct dp_catalog *dp_catalog, bool not_ack) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 dsc_dto; + + dsc_dto = dp_read_p0(catalog, MMSS_DP_DSC_DTO); + if (not_ack) + dsc_dto &= ~BIT(1); + else + dsc_dto = BIT(1); + + dp_write_p0(catalog, MMSS_DP_DSC_DTO, dsc_dto); +} + void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog) { struct dp_catalog_private *catalog = container_of(dp_catalog, @@ -429,6 +506,15 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, } } +static void dp_catalog_sdp_update( struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01); + dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00); +} + void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 colorimetry_cfg, u32 test_bits_depth) @@ -504,7 +590,6 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, drm_dbg_dp(catalog->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid); dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid); dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid); - dp_write_p0(catalog, MMSS_DP_DSC_DTO, 0x0); } int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, @@ -918,6 +1003,58 @@ void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog) dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0); } +void dp_catalog_dsc_commit_pps(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data; + int i; + + dp_write_link(catalog, DP_PPS_HB_0_3, 0x7F1000); + dp_write_link(catalog, DP_PPS_PB_0_3, 0xA22300); + + for (i = 0; i < dsc_data->parity_word_len; i++) + dp_write_link(catalog, DP_PPS_PB_4_7 + (i << 2), + dsc_data->parity_word[i]); + + for (i = 0; i < dsc_data->pps_word_len; i++) + dp_write_link(catalog, DP_PPS_PPS_0_3 + (i << 2), + dsc_data->pps_word[i]); +} + +static void dp_catalog_dp_flush(struct dp_catalog *dp_catalog, + enum dp_flush_bit flush_bit) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 dp_flush; + struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data; + + dp_flush = dp_read_link(catalog, MMSS_DP_FLUSH); + + dsc_data->continuous_pps = true; + + if ((flush_bit == DP_PPS_FLUSH) && dsc_data->continuous_pps) + dp_flush &= ~BIT(2); + + dp_flush |= BIT(flush_bit); + dp_write_link(catalog, MMSS_DP_FLUSH, dp_flush); + + /* + * TODO: no dp_config_sdp_update() required? + */ + dp_catalog_sdp_update(dp_catalog); +} + +void dp_catalog_pps_flush(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + dp_catalog_dp_flush(dp_catalog, DP_PPS_FLUSH); + drm_dbg_dp(catalog->drm_dev, "pps flush\n"); +} + struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) { struct dp_catalog_private *catalog; diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 990c162..537fb8d 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -62,6 +62,27 @@ enum dp_catalog_audio_header_type { DP_AUDIO_SDP_HEADER_MAX, }; +struct dp_dsc_cfg_data { + bool dsc_en; + bool continuous_pps; + char pps[128]; + u32 pps_len; + u32 pps_word[32]; + u32 pps_word_len; + u8 parity[32]; + u8 parity_len; + u32 parity_word[8]; + u32 parity_word_len; + u32 slice_per_pkt; + u32 bytes_per_pkt; + u32 eol_byte_num; + u32 be_in_lane; + u32 dto_en; + u32 dto_n; + u32 dto_d; + u32 dto_count; +}; + struct dp_catalog { u32 aux_data; u32 total; @@ -72,8 +93,74 @@ struct dp_catalog { enum dp_catalog_audio_header_type sdp_header; u32 audio_data; bool wide_bus_en; + struct dp_dsc_cfg_data dsc_data; }; +static inline u8 dp_ecc_get_g0_value(u8 data) +{ + u8 c[4]; + u8 g[4]; + u8 ret_data = 0; + u8 i; + + for (i = 0; i < 4; i++) + c[i] = (data >> i) & 0x01; + + g[0] = c[3]; + g[1] = c[0] ^ c[3]; + g[2] = c[1]; + g[3] = c[2]; + + for (i = 0; i < 4; i++) + ret_data = ((g[i] & 0x01) << i) | ret_data; + + return ret_data; +} + +static inline u8 dp_ecc_get_g1_value(u8 data) +{ + u8 c[4]; + u8 g[4]; + u8 ret_data = 0; + u8 i; + + for (i = 0; i < 4; i++) + c[i] = (data >> i) & 0x01; + + g[0] = c[0] ^ c[3]; + g[1] = c[0] ^ c[1] ^ c[3]; + g[2] = c[1] ^ c[2]; + g[3] = c[2] ^ c[3]; + + for (i = 0; i < 4; i++) + ret_data = ((g[i] & 0x01) << i) | ret_data; + + return ret_data; +} + +static inline u8 dp_header_get_parity(u32 data) +{ + u8 x0 = 0; + u8 x1 = 0; + u8 ci = 0; + u8 iData = 0; + u8 i = 0; + u8 parity_byte; + u8 num_byte = (data > 0xFF) ? 8 : 2; + + for (i = 0; i < num_byte; i++) { + iData = (data >> i*4) & 0xF; + + ci = iData ^ x1; + x1 = x0 ^ dp_ecc_get_g1_value(ci); + x0 = dp_ecc_get_g0_value(ci); + } + + parity_byte = x1 | (x0 << 4); + + return parity_byte; +} + /* Debug module */ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *disp_state); @@ -137,4 +224,10 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *catalog); void dp_catalog_audio_init(struct dp_catalog *catalog); void dp_catalog_audio_sfe_level(struct dp_catalog *catalog); +void dp_catalog_fec_config(struct dp_catalog *dp_catalog, bool enable); +void dp_catalog_dsc_commit_pps(struct dp_catalog *catalog); +void dp_catalog_config_dsc_dto(struct dp_catalog *catalog); +void dp_catalog_override_ack_dto(struct dp_catalog *dp_catalog, bool not_ack); +void dp_catalog_pps_flush(struct dp_catalog *catalog); + #endif /* _DP_CATALOG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index ae9c2b8..b315bf3 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -134,9 +134,13 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) tbd = dp_link_get_test_bits_depth(ctrl->link, ctrl->panel->dp_mode.bpp); - if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) { + /* + * since dsc encoder output byte stream to dp controller, + * 8 bits bpc should be used as long as dsc eanabled + */ + if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN || ctrl->panel->dsc_en) { pr_debug("BIT_DEPTH not set. Configure default\n"); - tbd = DP_TEST_BIT_DEPTH_8; + tbd = DP_TEST_BIT_DEPTH_8 >> DP_TEST_BIT_DEPTH_SHIFT; } config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT; @@ -366,8 +370,8 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, tu->lwidth_fp = drm_fixp_from_fraction(in->hactive, 1); tu->orig_lwidth = in->hactive; tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1); - tu->orig_hbp = in->hporch; - tu->rb2 = (in->hporch <= 80) ? 1 : 0; + tu->orig_hbp = in->hporch; + tu->rb2 = (in->hporch < 160) ? 1 : 0; if (tu->pixelEnc == 420) { temp1_fp = drm_fixp_from_fraction(2, 1); @@ -399,6 +403,8 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, if (!in->dsc_en) goto fec_check; + tu->bpp = 24; /* hardcode to 24 if DSC is enabled */ + temp1_fp = drm_fixp_from_fraction(in->compress_ratio, 100); temp2_fp = drm_fixp_from_fraction(in->bpp, 1); temp3_fp = drm_fixp_div(temp2_fp, temp1_fp); @@ -1076,6 +1082,11 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, { struct dp_tu_calc_input in; struct drm_display_mode *drm_mode; + struct dp_panel_info *timing; + struct msm_compression_info *comp_info; + + timing = &ctrl->panel->dp_mode.timing; + comp_info = &timing->comp_info; drm_mode = &ctrl->panel->dp_mode.drm_mode; @@ -1086,12 +1097,22 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, in.nlanes = ctrl->link->link_params.num_lanes; in.bpp = ctrl->panel->dp_mode.bpp; in.pixel_enc = 444; - in.dsc_en = 0; + in.dsc_en = ctrl->panel->dsc_en; in.async_en = 0; - in.fec_en = 0; + in.fec_en = ctrl->panel->fec_en; in.num_of_dsc_slices = 0; in.compress_ratio = 100; + + /* + * TODO: only one dsc slice supported for now + */ + if (ctrl->panel->dsc_en) { + in.num_of_dsc_slices = 1; + in.compress_ratio = mult_frac(100, comp_info->src_bpp, + comp_info->tgt_bpp); + } + _dp_ctrl_calc_tu(ctrl, &in, tu_table); } @@ -1424,6 +1445,74 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, return ret; } +static void dp_ctrl_sink_fec_enable(struct dp_ctrl_private *ctrl) +{ + int rlen; + + rlen = drm_dp_dpcd_writeb(ctrl->aux, DP_FEC_CONFIGURATION, 0x07); + if (rlen < 1) + DRM_ERROR("failed to enable sink fec\n"); + + +} + +static void dp_ctrl_host_fec_start(struct dp_ctrl_private *ctrl) +{ + u8 fec_sts = 0; + int i, max_retries = 3; + bool fec_en_detected = false; + + if (!ctrl->panel->fec_en) + return; + + /* Need to try to enable multiple times due to BS symbols collisions */ + for (i = 0; i < max_retries; i++) { + dp_catalog_fec_config(ctrl->catalog, true); + + /* wait for controller to start fec sequence */ + usleep_range(900, 1000); + + /* read back FEC status and check if it is enabled */ + drm_dp_dpcd_readb(ctrl->aux, DP_FEC_STATUS, &fec_sts); + if (fec_sts & DP_FEC_DECODE_EN_DETECTED) { + fec_en_detected = true; + break; + } + } + + drm_dbg_dp(ctrl->drm_dev, "retries %d, fec_en_detected %d\n", + i, fec_en_detected); + + if (!fec_en_detected) + DRM_ERROR("failed to enable sink fec\n"); +} + +static void dp_ctrl_host_fec_stop(struct dp_ctrl_private *ctrl) +{ + dp_catalog_fec_config(ctrl->catalog, false); +} + +static void dp_ctrl_sink_dsc_enable(struct dp_ctrl_private *ctrl) +{ + int rlen; + u32 dsc_enable; + u8 xx = 0; + + + if (!ctrl->panel->fec_en) + return; + + dsc_enable = ctrl->panel->dsc_en ? 1 : 0; + rlen = drm_dp_dpcd_writeb(ctrl->aux, DP_DSC_ENABLE, dsc_enable); + if (rlen < 1) + DRM_ERROR("failed to enable sink dsc\n"); + + + dsc_enable = 0; + drm_dp_dpcd_readb(ctrl->aux, DP_DSC_ENABLE, &xx); + +} + static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, int *training_step) { @@ -1442,6 +1531,9 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, * a link training pattern, we have to first do soft reset. */ + if (ctrl->panel->fec_en) + dp_ctrl_sink_fec_enable(ctrl); + ret = dp_ctrl_link_train(ctrl, training_step); return ret; @@ -1986,14 +2078,25 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) */ reinit_completion(&ctrl->video_comp); + if (ctrl->panel->dsc_en) + dp_panel_config_dsc(ctrl->panel, true); + dp_ctrl_configure_source_params(ctrl); dp_catalog_ctrl_config_msa(ctrl->catalog, ctrl->link->link_params.rate, pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl)); + if (ctrl->panel->dsc_en) { + dp_catalog_config_dsc_dto(ctrl->catalog); + dp_catalog_dsc_commit_pps(ctrl->catalog); + dp_catalog_pps_flush(ctrl->catalog); + } + dp_ctrl_setup_tr_unit(ctrl); + dp_catalog_override_ack_dto(ctrl->catalog, true); + dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); ret = dp_ctrl_wait4video_ready(ctrl); @@ -2004,6 +2107,12 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) drm_dbg_dp(ctrl->drm_dev, "mainlink %s\n", mainlink_ready ? "READY" : "NOT READY"); + if (ctrl->panel->dsc_en) { + /* wait for link training completion before fec config as per spec */ + dp_ctrl_host_fec_start(ctrl); + dp_ctrl_sink_dsc_enable(ctrl); + } + end: return ret; } @@ -2019,6 +2128,9 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) dp_io = &ctrl->parser->io; phy = dp_io->phy; + if (ctrl->panel->dsc_en) + dp_panel_config_dsc(ctrl->panel, false); + /* set dongle to D3 (power off) mode */ dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true); @@ -2093,6 +2205,14 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl) dp_io = &ctrl->parser->io; phy = dp_io->phy; + if (ctrl->panel->dsc_en) { + dp_ctrl_host_fec_stop(ctrl); + dp_panel_config_dsc(ctrl->panel, false); + dp_catalog_config_dsc_dto(ctrl->catalog); + } + + dp_catalog_override_ack_dto(ctrl->catalog, false); + dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); dp_catalog_ctrl_reset(ctrl->catalog); diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index bde1a7c..da59d13 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #include @@ -99,7 +100,7 @@ struct dp_display_private { struct dp_debug *debug; struct dp_usbpd_cb usbpd_cb; - struct dp_display_mode dp_mode; + struct dp_display_mode *dp_mode; struct msm_dp dp_display; /* wait for audio signaling */ @@ -831,6 +832,9 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_link; } + /* both dp_display and dp_panel shared same dp_mode */ + dp->dp_mode = &dp->panel->dp_mode; + dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux, dp->power, dp->catalog, dp->parser); if (IS_ERR(dp->ctrl)) { @@ -1662,7 +1666,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge) bool force_link_train = false; dp_display = container_of(dp, struct dp_display_private, dp_display); - if (!dp_display->dp_mode.drm_mode.clock) { + if (!dp_display->dp_mode->drm_mode.clock) { DRM_ERROR("invalid params\n"); return; } @@ -1678,7 +1682,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge) return; } - rc = dp_display_set_mode(dp, &dp_display->dp_mode); + rc = dp_display_set_mode(dp, dp_display->dp_mode); if (rc) { DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); mutex_unlock(&dp_display->event_mutex); @@ -1744,6 +1748,10 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge) if (state == ST_DISCONNECT_PENDING) { /* completed disconnection */ dp_display->hpd_state = ST_DISCONNECTED; + if (dp_display->panel->dsc_en) { + dp_display->dp_mode->timing.comp_info.enabled = false; + dp_display->panel->dsc_en = false; + } } else { dp_display->hpd_state = ST_DISPLAY_OFF; } @@ -1762,23 +1770,50 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge, dp_display = container_of(dp, struct dp_display_private, dp_display); - memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode)); + memset(dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode)); if (dp_display_check_video_test(dp)) - dp_display->dp_mode.bpp = dp_display_get_test_bpp(dp); + dp_display->dp_mode->bpp = dp_display_get_test_bpp(dp); else /* Default num_components per pixel = 3 */ - dp_display->dp_mode.bpp = dp->connector->display_info.bpc * 3; + dp_display->dp_mode->bpp = dp->connector->display_info.bpc * 3; + + if (!dp_display->dp_mode->bpp) + dp_display->dp_mode->bpp = 24; /* Default bpp */ + + drm_mode_copy(&dp_display->dp_mode->drm_mode, adjusted_mode); + + dp_display->dp_mode->v_active_low = + !!(dp_display->dp_mode->drm_mode.flags & DRM_MODE_FLAG_NVSYNC); + + dp_display->dp_mode->h_active_low = + !!(dp_display->dp_mode->drm_mode.flags & DRM_MODE_FLAG_NHSYNC); + + + if (dp_display->panel->dsc_en) { + dp_display->dp_mode->capabilities |= DP_PANEL_CAPS_DSC; + dp_panel_convert_to_dp_mode(dp_display->panel, dp_display->dp_mode); + } +} - if (!dp_display->dp_mode.bpp) - dp_display->dp_mode.bpp = 24; /* Default bpp */ +void msm_dp_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + dp_bridge_mode_set(bridge, mode, adjusted_mode); +} - drm_mode_copy(&dp_display->dp_mode.drm_mode, adjusted_mode); +struct msm_compression_info *msm_dp_bridge_get_compression(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + struct dp_display_private *dp; + + dp = container_of(dp_display, struct dp_display_private, dp_display); - dp_display->dp_mode.v_active_low = - !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC); + if (!dp->panel->dsc_en) + return NULL; - dp_display->dp_mode.h_active_low = - !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); + return &dp->dp_mode->timing.comp_info; } void dp_bridge_hpd_enable(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 55bb6b0..19e2f07 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -5,11 +5,12 @@ */ #include "dp_panel.h" - +#include "dpu_dsc_helper.h" #include #include #include #include +#include #define DSC_TGT_BPP 10 @@ -612,6 +613,573 @@ u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel) return colorimetry; } +static inline int fixp2int_ceil(s64 a) +{ + return (a ? drm_fixp2int_ceil(a) : 0); +} + +struct dp_dsc_slices_per_line { + u32 min_ppr; + u32 max_ppr; + u8 num_slices; +}; + +struct dp_dsc_peak_throughput { + u32 index; + u32 peak_throughput; +}; + +struct dp_dsc_slice_caps_bit_map { + u32 num_slices; + u32 bit_index; +}; + +const struct dp_dsc_slices_per_line slice_per_line_tbl[] = { + {0, 340, 1 }, + {340, 680, 2 }, + {680, 1360, 4 }, + {1360, 3200, 8 }, + {3200, 4800, 12 }, + {4800, 6400, 16 }, + {6400, 8000, 20 }, + {8000, 9600, 24 } +}; + +const struct dp_dsc_peak_throughput peak_throughput_mode_0_tbl[] = { + {0, 0}, + {1, 340}, + {2, 400}, + {3, 450}, + {4, 500}, + {5, 550}, + {6, 600}, + {7, 650}, + {8, 700}, + {9, 750}, + {10, 800}, + {11, 850}, + {12, 900}, + {13, 950}, + {14, 1000}, +}; + +const struct dp_dsc_slice_caps_bit_map slice_caps_bit_map_tbl[] = { + {1, 0}, + {2, 1}, + {4, 3}, + {6, 4}, + {8, 5}, + {10, 6}, + {12, 7}, + {16, 0}, + {20, 1}, + {24, 2}, +}; + +static bool dp_panel_check_slice_support(u32 num_slices, u32 raw_data_1, + u32 raw_data_2) +{ + const struct dp_dsc_slice_caps_bit_map *bcap; + u32 raw_data; + int i; + + if (num_slices <= 12) + raw_data = raw_data_1; + else + raw_data = raw_data_2; + + for (i = 0; i < ARRAY_SIZE(slice_caps_bit_map_tbl); i++) { + bcap = &slice_caps_bit_map_tbl[i]; + + if (bcap->num_slices == num_slices) { + raw_data &= (1 << bcap->bit_index); + + if (raw_data) + return true; + else + return false; + } + } + + return false; +} + +static int dp_panel_dsc_prepare_basic_params( + struct msm_compression_info *comp_info, + const struct dp_display_mode *dp_mode, + struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct drm_dsc_config *dsc; + int i; + const struct dp_dsc_slices_per_line *rec; + const struct dp_dsc_peak_throughput *tput; + u32 slice_width; + u32 ppr = dp_mode->timing.pixel_clk_khz/1000; + u32 max_slice_width; + u32 ppr_max_index; + u32 peak_throughput; + u32 ppr_per_slice; + u32 slice_caps_1; + u32 slice_caps_2; + u32 dsc_version_major, dsc_version_minor; + bool dsc_version_supported = false; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + dsc_version_major = dp_panel->sink_dsc_caps.version & 0xF; + dsc_version_minor = (dp_panel->sink_dsc_caps.version >> 4) & 0xF; + dsc_version_supported = (dsc_version_major == 0x1 && + (dsc_version_minor == 0x1 || dsc_version_minor == 0x2)) + ? true : false; + + drm_dbg_dp(panel->drm_dev, "DSC version: %d.%d, dpcd value: %x\n", + dsc_version_major, dsc_version_minor, + dp_panel->sink_dsc_caps.version); + + if (!dsc_version_supported) { + dsc_version_major = 1; + dsc_version_minor = 1; + DRM_ERROR("invalid sink DSC version, fallback to %d.%d\n", + dsc_version_major, dsc_version_minor); + } + + dsc = &comp_info->msm_dsc_info.drm_dsc; + dsc->dsc_version_major = dsc_version_major; + dsc->dsc_version_minor = dsc_version_minor; + comp_info->msm_dsc_info.scr_rev = 0x0; + + + comp_info->msm_dsc_info.slice_per_pkt = 0; + for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) { + rec = &slice_per_line_tbl[i]; + if ((ppr > rec->min_ppr) && (ppr <= rec->max_ppr)) { + comp_info->msm_dsc_info.slice_per_pkt = rec->num_slices; + i++; + break; + } + } + + if (comp_info->msm_dsc_info.slice_per_pkt == 0) + return -EINVAL; + + ppr_max_index = dp_panel->dsc_dpcd[11] &= 0xf; + if (!ppr_max_index || ppr_max_index >= 15) { + drm_dbg_dp(panel->drm_dev, + "Throughput mode 0 not supported"); + return -EINVAL; + } + + tput = &peak_throughput_mode_0_tbl[ppr_max_index]; + peak_throughput = tput->peak_throughput; + + max_slice_width = dp_panel->dsc_dpcd[12] * 320; + slice_width = (dp_mode->timing.h_active / + comp_info->msm_dsc_info.slice_per_pkt); + + ppr_per_slice = ppr/comp_info->msm_dsc_info.slice_per_pkt; + + slice_caps_1 = dp_panel->dsc_dpcd[4]; + slice_caps_2 = dp_panel->dsc_dpcd[13] & 0x7; + + /* + * There are 3 conditions to check for sink support: + * 1. The slice width cannot exceed the maximum. + * 2. The ppr per slice cannot exceed the maximum. + * 3. The number of slices must be explicitly supported. + */ + while (slice_width >= max_slice_width || + ppr_per_slice > peak_throughput || + !dp_panel_check_slice_support( + comp_info->msm_dsc_info.slice_per_pkt, slice_caps_1, + slice_caps_2)) { + if (i == ARRAY_SIZE(slice_per_line_tbl)) + return -EINVAL; + + rec = &slice_per_line_tbl[i]; + comp_info->msm_dsc_info.slice_per_pkt = rec->num_slices; + slice_width = (dp_mode->timing.h_active / + comp_info->msm_dsc_info.slice_per_pkt); + ppr_per_slice = ppr/comp_info->msm_dsc_info.slice_per_pkt; + i++; + } + + dsc->block_pred_enable = dp_panel->sink_dsc_caps.block_pred_en; + + dsc->pic_width = dp_mode->timing.h_active; + dsc->pic_height = dp_mode->timing.v_active; + dsc->slice_width = slice_width; + + if (dsc->pic_height % 108 == 0) + dsc->slice_height = 108; + else if (dsc->pic_height % 16 == 0) + dsc->slice_height = 16; + else if (dsc->pic_height % 12 == 0) + dsc->slice_height = 12; + else + dsc->slice_height = 15; + + dsc->bits_per_component = (dp_mode->timing.bpp / 3); + dsc->bits_per_pixel = DSC_TGT_BPP << 4; + dsc->slice_count = DIV_ROUND_UP(dp_mode->timing.h_active, slice_width); + + comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC; + comp_info->tgt_bpp = DSC_TGT_BPP; + comp_info->src_bpp = dp_mode->timing.bpp; + comp_info->comp_ratio = dp_mode->timing.bpp / DSC_TGT_BPP; + comp_info->enabled = true; + + return 0; +} + +static void dp_panel_get_dto_params(u32 src_bpp, u32 tgt_bpp, u32 *num, u32 *denom) +{ + if ((tgt_bpp == 12) && (src_bpp == 24)) { + *num = 1; + *denom = 2; + } else if ((tgt_bpp == 15) && (src_bpp == 30)) { + *num = 5; + *denom = 8; + } else if ((tgt_bpp == 8) && ((src_bpp == 24) || (src_bpp == 30))) { + *num = 1; + *denom = 3; + } else if ((tgt_bpp == 10) && (src_bpp == 30)) { + *num = 5; + *denom = 12; + } else { + DRM_ERROR("dto params not found\n"); + *num = 0; + *denom = 1; + } +} + +static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct dp_dsc_cfg_data *dsc_data; + u8 *pps, *parity; + u32 *pps_word, *parity_word; + int i, index_4; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + dsc_data = &panel->catalog->dsc_data; + pps = dsc_data->pps; + pps_word = dsc_data->pps_word; + parity = dsc_data->parity; + parity_word = dsc_data->parity_word; + + memset(parity, 0, sizeof(dsc_data->parity)); + + dsc_data->pps_word_len = dsc_data->pps_len >> 2; + dsc_data->parity_len = dsc_data->pps_word_len; + dsc_data->parity_word_len = (dsc_data->parity_len >> 2) + 1; + + for (i = 0; i < dsc_data->pps_word_len; i++) { + index_4 = i << 2; + pps_word[i] = pps[index_4 + 0] << 0 | + pps[index_4 + 1] << 8 | + pps[index_4 + 2] << 16 | + pps[index_4 + 3] << 24; + + parity[i] = dp_header_get_parity(pps_word[i]); + } + + for (i = 0; i < dsc_data->parity_word_len; i++) { + index_4 = i << 2; + parity_word[i] = parity[index_4 + 0] << 0 | + parity[index_4 + 1] << 8 | + parity[index_4 + 2] << 16 | + parity[index_4 + 3] << 24; + } +} + +void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable) +{ + struct dp_panel_private *panel; + struct dp_panel_info *timing; + struct msm_compression_info *comp_info; + struct dp_dsc_cfg_data *dsc_data; + struct drm_dsc_picture_parameter_set *pps_payload; + struct drm_dsc_config *dsc; + + if (!dp_panel->dsc_en) + return; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + dsc_data = &panel->catalog->dsc_data; + timing = &dp_panel->dp_mode.timing; + comp_info = &timing->comp_info; + dsc = &comp_info->msm_dsc_info.drm_dsc; + + if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) { + memset(dsc_data->pps, 0, sizeof(dsc_data->pps)); + pps_payload = (struct drm_dsc_picture_parameter_set *)dsc_data->pps; + drm_dsc_pps_payload_pack(pps_payload, dsc); + + dsc_data->pps_len = DSC_1_1_PPS_PARAMETER_SET_ELEMENTS; + dp_panel_dsc_prepare_pps_packet(dp_panel); + + dsc_data->slice_per_pkt = comp_info->msm_dsc_info.slice_per_pkt - 1; + dsc_data->bytes_per_pkt = comp_info->msm_dsc_info.bytes_per_pkt; + dsc_data->bytes_per_pkt /= comp_info->msm_dsc_info.slice_per_pkt; + dsc_data->eol_byte_num = comp_info->msm_dsc_info.eol_byte_num; + dsc_data->dto_count = comp_info->msm_dsc_info.pclk_per_line; + dsc_data->be_in_lane = 10; + dsc_data->dsc_en = true; + dsc_data->dto_en = true; + dp_panel_get_dto_params(comp_info->src_bpp, comp_info->tgt_bpp, &dsc_data->dto_n, + &dsc_data->dto_d); + } else { + dsc_data->dsc_en = false; + dsc_data->dto_en = false; + dsc_data->dto_n = 0; + dsc_data->dto_d = 0; + dsc_data->continuous_pps = false; + } +} + +static void _dp_panel_dsc_get_num_extra_pclk(struct msm_compression_info *comp_info) +{ + unsigned int dto_n = 0, dto_d = 0, remainder; + int ack_required, last_few_ack_required, accum_ack; + int last_few_pclk, last_few_pclk_required; + struct msm_display_dsc_info *dsc_info = &comp_info->msm_dsc_info; + int start, temp, line_width = dsc_info->drm_dsc.pic_width/2; + s64 temp1_fp, temp2_fp; + + dp_panel_get_dto_params(comp_info->src_bpp, comp_info->tgt_bpp, &dto_n, &dto_d); + + ack_required = dsc_info->pclk_per_line; + + /* number of pclk cycles left outside of the complete DTO set */ + last_few_pclk = line_width % dto_d; + + /* number of pclk cycles outside of the complete dto */ + temp1_fp = drm_fixp_from_fraction(line_width, dto_d); + temp2_fp = drm_fixp_from_fraction(dto_n, 1); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + temp = drm_fixp2int(temp1_fp); + last_few_ack_required = ack_required - temp; + + /* + * check how many more pclk is needed to + * accommodate the last few ack required + */ + remainder = dto_n; + accum_ack = 0; + last_few_pclk_required = 0; + while (accum_ack < last_few_ack_required) { + last_few_pclk_required++; + + if (remainder >= dto_n) + start = remainder; + else + start = remainder + dto_d; + + remainder = start - dto_n; + if (remainder < dto_n) + accum_ack++; + } + + /* if fewer pclk than required */ + if (last_few_pclk < last_few_pclk_required) + dsc_info->extra_width = last_few_pclk_required - last_few_pclk; + else + dsc_info->extra_width = 0; +} + +static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel, + struct msm_display_dsc_info *dsc_info, + struct dp_display_mode *dp_mode, u32 dsc_byte_cnt) +{ + int num_slices, tot_num_eoc_symbols; + int tot_num_hor_bytes, tot_num_dummy_bytes; + int dwidth_dsc_bytes, eoc_bytes; + u32 num_lanes; + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + num_lanes = panel->link->link_params.num_lanes; + num_slices = dsc_info->slice_per_pkt; + + eoc_bytes = dsc_byte_cnt % num_lanes; + tot_num_eoc_symbols = num_lanes * num_slices; + tot_num_hor_bytes = dsc_byte_cnt * num_slices; + tot_num_dummy_bytes = (num_lanes - eoc_bytes) * num_slices; + + if (!eoc_bytes) + tot_num_dummy_bytes = 0; + + dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols + + tot_num_dummy_bytes; + + drm_dbg_dp(panel->drm_dev, "dwidth_dsc_bytes:%d, tot_num_hor_bytes:%d\n", + dwidth_dsc_bytes, tot_num_hor_bytes); + + dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, + tot_num_hor_bytes); + + dp_mode->timing.dsc_overhead_fp = dp_mode->dsc_overhead_fp; +} + +static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, + struct msm_compression_info *comp_info, + struct dp_display_mode *dp_mode) +{ + int comp_ratio = 100, intf_width; + int slice_per_pkt, slice_per_intf; + s64 temp1_fp, temp2_fp; + s64 numerator_fp, denominator_fp; + s64 dsc_byte_count_fp; + u32 dsc_byte_count, temp1, temp2; + struct msm_display_dsc_info *dsc_info = &comp_info->msm_dsc_info; + + intf_width = dp_mode->timing.h_active; + if (!dsc_info || !dsc_info->drm_dsc.slice_width || !dsc_info->slice_per_pkt || + (intf_width < dsc_info->drm_dsc.slice_width)) + return; + + slice_per_pkt = dsc_info->slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, + dsc_info->drm_dsc.slice_width); + + comp_ratio = mult_frac(100, comp_info->src_bpp, comp_info->tgt_bpp); + + temp1_fp = drm_fixp_from_fraction(comp_ratio, 100); + temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1); + denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp); + numerator_fp = drm_fixp_from_fraction( + intf_width * dsc_info->drm_dsc.bits_per_component * 3, 1); + dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp); + dsc_byte_count = fixp2int_ceil(dsc_byte_count_fp); + + temp1 = dsc_byte_count * slice_per_intf; + temp2 = temp1; + if (temp1 % 3 != 0) + temp1 += 3 - (temp1 % 3); + + dsc_info->eol_byte_num = temp1 - temp2; + + temp1_fp = drm_fixp_from_fraction(slice_per_intf, 6); + temp2_fp = drm_fixp_mul(dsc_byte_count_fp, temp1_fp); + dsc_info->pclk_per_line = fixp2int_ceil(temp2_fp); + + _dp_panel_dsc_get_num_extra_pclk(comp_info); + dsc_info->pclk_per_line--; + + _dp_panel_dsc_bw_overhead_calc(dp_panel, dsc_info, dp_mode, dsc_byte_count); +} + +void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, + struct dp_display_mode *dp_mode) +{ + struct dp_panel_private *panel; + const u32 num_components = 3, default_bpp = 24; + struct drm_display_mode *drm_mode; + struct dp_panel_info *timing; + struct msm_compression_info *comp_info; + bool dsc_cap = (dp_mode->capabilities & DP_PANEL_CAPS_DSC) ? + true : false; + int rc; + + if (!dp_panel->dsc_en) + return; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + drm_mode = &dp_mode->drm_mode; + timing = &dp_mode->timing; + + timing->h_active = drm_mode->hdisplay; + timing->h_back_porch = drm_mode->htotal - drm_mode->hsync_end; + timing->h_sync_width = drm_mode->htotal - + (drm_mode->hsync_start + dp_mode->timing.h_back_porch); + + timing->h_front_porch = drm_mode->hsync_start - + drm_mode->hdisplay; + timing->h_skew = drm_mode->hskew; + + timing->v_active = drm_mode->vdisplay; + timing->v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; + timing->v_sync_width = drm_mode->vtotal - + (drm_mode->vsync_start + dp_mode->timing.v_back_porch); + + timing->v_front_porch = drm_mode->vsync_start - drm_mode->vdisplay; + + timing->refresh_rate = drm_mode_vrefresh(drm_mode); + timing->pixel_clk_khz = drm_mode->clock; + + timing->v_active_low = + !!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC); + + timing->h_active_low = + !!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC); + + timing->bpp = + dp_panel->connector->display_info.bpc * num_components; + if (!timing->bpp) + timing->bpp = default_bpp; + + timing->widebus_en = dp_panel->widebus_en; + timing->dsc_overhead_fp = 0; + + comp_info = &timing->comp_info; + comp_info->src_bpp = default_bpp; + comp_info->tgt_bpp = default_bpp; + comp_info->comp_type = MSM_DISPLAY_COMPRESSION_NONE; + comp_info->comp_ratio = 1; + comp_info->enabled = false; + + /* As YUV was not supported now, so set the default format to RGB */ + dp_mode->output_format = DP_OUTPUT_FORMAT_RGB; + /* + * If a given videomode can be only supported in YCBCR420, set + * the output format to YUV420. While now our driver did not + * support YUV display over DP, so just place this flag here. + * When we want to support YUV, we can use this flag to do + * a lot of settings, like CDM, CSC and pixel_clock. + */ + if (drm_mode_is_420_only(&dp_panel->connector->display_info, + drm_mode)) { + dp_mode->output_format = DP_OUTPUT_FORMAT_YCBCR420; + drm_dbg_dp(panel->drm_dev, "YCBCR420 was not supported"); + } + + timing->bpp = dp_panel_get_mode_bpp(dp_panel, + timing->bpp, timing->pixel_clk_khz); + + + if (dp_panel->dsc_en && dsc_cap) { + if (dp_panel_dsc_prepare_basic_params(comp_info, + dp_mode, dp_panel)) { + drm_dbg_dp(panel->drm_dev, + "prepare DSC basic params failed\n"); + return; + } + + rc = dpu_dsc_populate_dsc_config(&comp_info->msm_dsc_info.drm_dsc, 0); + if (rc) { + drm_dbg_dp(panel->drm_dev, + "failed populating dsc params \n"); + return; + } + + rc = dpu_dsc_populate_dsc_private_params(&comp_info->msm_dsc_info, + dp_mode->timing.h_active); + if (rc) { + drm_dbg_dp(panel->drm_dev, + "failed populating other dsc params\n"); + return; + } + + dp_panel_dsc_pclk_param_calc(dp_panel, comp_info, dp_mode); + } + dp_mode->fec_overhead_fp = dp_panel->fec_overhead_fp; +} + struct dp_panel *dp_panel_get(struct dp_panel_in *in) { struct dp_panel_private *panel; diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 4c45d51..576056c 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -112,6 +112,7 @@ struct dp_panel { bool fec_feature_enable; bool dsc_en; bool fec_en; + bool widebus_en; s64 fec_overhead_fp; }; @@ -128,6 +129,9 @@ int dp_panel_get_modes(struct dp_panel *dp_panel, void dp_panel_handle_sink_request(struct dp_panel *dp_panel); void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable); u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel); +void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable); +void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, + struct dp_display_mode *dp_mode); /** * is_link_rate_valid() - validates the link rate diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h index 2686028..96d48d0c 100644 --- a/drivers/gpu/drm/msm/dp/dp_reg.h +++ b/drivers/gpu/drm/msm/dp/dp_reg.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #ifndef _DP_REG_H_ @@ -167,7 +168,38 @@ #define MMSS_DP_PSR_CRC_RG (0x00000154) #define MMSS_DP_PSR_CRC_B (0x00000158) -#define REG_DP_COMPRESSION_MODE_CTRL (0x00000180) +#define DP_COMPRESSION_MODE_CTRL (0x00000180) +#define DP_PPS_HB_0_3 (0x00000184) +#define DP_PPS_PB_0_3 (0x00000188) +#define DP_PPS_PB_4_7 (0x0000018C) +#define DP_PPS_PB_8_11 (0x00000190) +#define DP_PPS_PB_12_15 (0x00000194) +#define DP_PPS_PB_16_19 (0x00000198) +#define DP_PPS_PB_20_23 (0x0000019C) +#define DP_PPS_PB_24_27 (0x000001A0) +#define DP_PPS_PB_28_31 (0x000001A4) +#define DP_PPS_PPS_0_3 (0x000001A8) +#define DP_PPS_PPS_4_7 (0x000001AC) +#define DP_PPS_PPS_8_11 (0x000001B0) +#define DP_PPS_PPS_12_15 (0x000001B4) +#define DP_PPS_PPS_16_19 (0x000001B8) +#define DP_PPS_PPS_20_23 (0x000001BC) +#define DP_PPS_PPS_24_27 (0x000001C0) +#define DP_PPS_PPS_28_31 (0x000001C4) +#define DP_PPS_PPS_32_35 (0x000001C8) +#define DP_PPS_PPS_36_39 (0x000001CC) +#define DP_PPS_PPS_40_43 (0x000001D0) +#define DP_PPS_PPS_44_47 (0x000001D4) +#define DP_PPS_PPS_48_51 (0x000001D8) +#define DP_PPS_PPS_52_55 (0x000001DC) +#define DP_PPS_PPS_56_59 (0x000001E0) +#define DP_PPS_PPS_60_63 (0x000001E4) +#define DP_PPS_PPS_64_67 (0x000001E8) +#define DP_PPS_PPS_68_71 (0x000001EC) +#define DP_PPS_PPS_72_75 (0x000001F0) +#define DP_PPS_PPS_76_79 (0x000001F4) +#define DP_PPS_PPS_80_83 (0x000001F8) +#define DP_PPS_PPS_84_87 (0x000001FC) #define MMSS_DP_AUDIO_CFG (0x00000200) #define MMSS_DP_AUDIO_STATUS (0x00000204) @@ -178,6 +210,8 @@ #define MMSS_DP_SDP_CFG (0x00000228) #define MMSS_DP_SDP_CFG2 (0x0000022C) +#define MMSS_DP_SDP_CFG3 (0x0000024C) +#define MMSS_DP_SDP_CFG4 (0x000004EC) #define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000230) #define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000234) @@ -210,6 +244,9 @@ #define MMSS_DP_AUDIO_INFOFRAME_1 (0x000002AC) #define MMSS_DP_AUDIO_INFOFRAME_2 (0x000002B0) +#define MMSS_DP_FLUSH (0x000002F8) +#define MMSS_DP1_FLUSH (0x000002FC) + #define MMSS_DP_GENERIC0_0 (0x00000300) #define MMSS_DP_GENERIC0_1 (0x00000304) #define MMSS_DP_GENERIC0_2 (0x00000308) @@ -268,6 +305,7 @@ #define MMSS_DP_TPG_MAIN_CONTROL (0x00000060) #define MMSS_DP_DSC_DTO (0x0000007C) +#define MMSS_DP_DSC_DTO_COUNT (0x00000084) #define DP_TPG_CHECKERED_RECT_PATTERN (0x00000100) #define MMSS_DP_TPG_VIDEO_CONFIG (0x00000064) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index cf4eb8d..6a46ed7 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -476,6 +476,11 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_displa void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor); bool msm_dp_wide_bus_available(const struct msm_dp *dp_display); +struct msm_compression_info *msm_dp_bridge_get_compression(struct drm_bridge *drm_bridge); + +void msm_dp_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); #else static inline int __init msm_dp_register(void) @@ -510,6 +515,17 @@ static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) return false; } +static inline struct msm_compression_info *msm_dp_bridge_get_compression( + struct drm_bridge *drm_bridge) +{ + return NULL; +} +static inline void msm_dp_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} #endif #ifdef CONFIG_DRM_MSM_MDP4 From patchwork Mon Jan 23 18:24:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112740 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A9D93C25B50 for ; Mon, 23 Jan 2023 18:25:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232251AbjAWSZs (ORCPT ); Mon, 23 Jan 2023 13:25:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233777AbjAWSZS (ORCPT ); Mon, 23 Jan 2023 13:25:18 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5EE72EFBF; Mon, 23 Jan 2023 10:25:09 -0800 (PST) Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NHpH8B007546; Mon, 23 Jan 2023 18:25:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=kGXLYCh3iftJMOPO5f8v5fkwCr+BJkWzkAKWWxI7DcU=; b=gba2bxk8mbw3gAiTSod4bCk3hLqbYjqr9XzRyCB4KTrKwX1MlGLlq02wc6HQu5vZUm+h dLiR8Mw7/ZIsyxk0mhxWTokUzvYAY54HkZEkpH3nkrUS0iSmdvVccnU10HVjzz9x4okl Pjq7Nl3TdtdKrRhvW2YIYSI2Cnzfz0bbVCjuLioDmyrPqmVRZ9sj8HebwHdNjhKfW42D yaPgG8hBjiszKyjiMsLoFq99fw+pY0Q+eYJ3n1iiSU9VkYJ+kyvEmoHGMLLvVjuwbeN6 pjB+Gw1iAh0g73jHUMMkTH/b3VG71YnBeTh19DKaDcQ9ZtAyFE0AVdIKI9kNYiVit6Ae DQ== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89fm3jxh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:02 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIP1BX003519 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:01 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:25:01 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Date: Mon, 23 Jan 2023 10:24:29 -0800 Message-ID: <1674498274-6010-10-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: CnsyO8wtVBSpnmKYkTFVwLjj30g_oAuA X-Proofpoint-GUID: CnsyO8wtVBSpnmKYkTFVwLjj30g_oAuA X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 clxscore=1015 malwarescore=0 bulkscore=0 phishscore=0 lowpriorityscore=0 mlxlogscore=999 mlxscore=0 priorityscore=1501 adultscore=0 suspectscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230176 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org struct msm_compression_info is used to support several different compression mechanisms. It also contains customized info required to configure DSC encoder engine. This patch also make changes DSI module to have DSI exports struct msm_compreion_info to dpu encoder instead of struct drm_dsc_config. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 7 +++++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 4 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 10 ++++++++-- drivers/gpu/drm/msm/dsi/dsi.c | 3 ++- drivers/gpu/drm/msm/dsi/dsi.h | 3 ++- drivers/gpu/drm/msm/dsi/dsi_host.c | 14 ++++++++++++-- drivers/gpu/drm/msm/msm_drv.h | 4 ++-- 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 758261e..7f4a439 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2013 Red Hat * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * * Author: Rob Clark */ @@ -210,6 +210,7 @@ struct dpu_encoder_virt { /* DSC configuration */ struct drm_dsc_config *dsc; + struct msm_compression_info *comp_info; }; #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base) @@ -2275,7 +2276,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, dpu_enc->idle_pc_supported = dpu_kms->catalog->caps->has_idle_pc; - dpu_enc->dsc = disp_info->dsc; + dpu_enc->comp_info = disp_info->comp_info; + if (dpu_enc->comp_info) + dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc; mutex_lock(&dpu_enc->enc_lock); for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 9e7236e..bd2da5e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -36,7 +36,7 @@ struct msm_display_info { uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY]; bool is_cmd_mode; bool is_te_using_watchdog_timer; - struct drm_dsc_config *dsc; + struct msm_compression_info *comp_info; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index d612419..70a74ed 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2013 Red Hat * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * * Author: Rob Clark */ @@ -570,7 +570,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, info.h_tile_instance[info.num_of_h_tiles++] = i; info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]); - info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]); + info.comp_info = msm_dsi_get_dsc_config(priv->dsi[i]); if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) { rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder); @@ -622,6 +622,8 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, info.num_of_h_tiles = 1; info.h_tile_instance[0] = i; info.intf_type = encoder->encoder_type; + info.is_cmd_mode = 0; /* dp always video mode */ + info.comp_info = NULL; rc = dpu_encoder_setup(dev, encoder, &info); if (rc) { DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n", @@ -892,6 +894,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k pm_runtime_get_sync(&dpu_kms->pdev->dev); + for (i = 0; i < cat->dsc_count; i++) + msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len, + dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i); + /* dump CTL sub-blocks HW regs info */ for (i = 0; i < cat->ctl_count; i++) msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len, diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 31fdee2..52b7e33 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #include "dsi.h" @@ -13,7 +14,7 @@ bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi) return !(host_flags & MIPI_DSI_MODE_VIDEO); } -struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) +struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) { return msm_dsi_host_get_dsc_config(msm_dsi->host); } diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index bd3763a..79ada54 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #ifndef __DSI_CONNECTOR_H__ @@ -133,7 +134,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi); int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi); void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host); void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host); -struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host); +struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host); /* dsi phy */ struct msm_dsi_phy; diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 18fa30e..6188f4b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved */ #include @@ -163,6 +164,7 @@ struct msm_dsi_host { struct drm_display_mode *mode; struct drm_dsc_config *dsc; + struct msm_compression_info comp_info; /* connected device info */ unsigned int channel; @@ -2600,9 +2602,17 @@ void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host) DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER); } -struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host) +struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + struct msm_compression_info *comp_info = NULL; - return msm_host->dsc; + if (msm_host->dsc) { + comp_info = &msm_host->comp_info; + comp_info->msm_dsc_info.drm_dsc = *msm_host->dsc; + comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC; + comp_info->enabled = true; + } + + return comp_info; } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 6a46ed7..eab0901 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -430,7 +430,7 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi); bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi); bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi); -struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi); +struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi); #else static inline void __init msm_dsi_register(void) { @@ -460,7 +460,7 @@ static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi) return false; } -static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) +static inline struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi) { return NULL; } From patchwork Mon Jan 23 18:24:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112744 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C19FC54EAA for ; Mon, 23 Jan 2023 18:26:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233955AbjAWSZ7 (ORCPT ); Mon, 23 Jan 2023 13:25:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36386 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233907AbjAWSZt (ORCPT ); Mon, 23 Jan 2023 13:25:49 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DB2BD32539; Mon, 23 Jan 2023 10:25:13 -0800 (PST) Received: from pps.filterd (m0279870.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NHwlC3017544; Mon, 23 Jan 2023 18:25:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=D78bHH1o8c5IjkgzIwMACnek/mpsoDCV8RIUxEZzQxQ=; b=aGdxNkho5AeVN9VwXQ4XRzxQITqVfK/cYxBJgLj5aVNR+OWvvs9bW7MJRclTx3IwQ9li IvYitKxuPA0yt/cBRKMG3UM9v8ft8IhIjwJU7qqnYTqSWbBAzgGrj1tIZ3EF/jvEkxIG SVEKOCSyqeqljRtZIwxLmFNgdtcbOcDcc4Xv94hGvYB13i0fmMDS2uz+TmkniuU5nrrw B44rTc3LqxGOcZiLt6/j3pJUalm19hUlZOKKk3+j0dWHhWbKXogwP3PyshLiCG7nUMh7 AENCmiSxHxvz+ywz96120VjeOcoFMSrZSQs+99eswqENsbEcwMcadlXz1IXcfpXSO0L8 KA== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89pwbj9u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:04 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIP3hi003569 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:03 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:25:02 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Date: Mon, 23 Jan 2023 10:24:30 -0800 Message-ID: <1674498274-6010-11-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: J8WmUijaKc5WZFZxndJLxF-xi3oVZf2I X-Proofpoint-GUID: J8WmUijaKc5WZFZxndJLxF-xi3oVZf2I X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 phishscore=0 clxscore=1015 impostorscore=0 suspectscore=0 bulkscore=0 adultscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 lowpriorityscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230176 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org DSC V1.2 encoder engine is newly added hardware module. This patch add support functions to configure and enable DSC V1.2 encoder engine. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 60 +++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c | 23 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 23 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 371 +++++++++++++++++++++++++ 6 files changed, 463 insertions(+), 17 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 28cf52b..271c29a15 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \ disp/dpu1/dpu_hw_catalog.o \ disp/dpu1/dpu_hw_ctl.o \ disp/dpu1/dpu_hw_dsc.o \ + disp/dpu1/dpu_hw_dsc_1_2.o \ disp/dpu1/dpu_dsc_helper.o \ disp/dpu1/dpu_hw_interrupts.o \ disp/dpu1/dpu_hw_intf.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 7f4a439..901e317 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1821,7 +1821,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc, u32 initial_lines) { if (hw_dsc->ops.dsc_config) - hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines); + hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false); if (hw_dsc->ops.dsc_config_thresh) hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 978e3bd..7b0b092 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */ @@ -11,6 +11,7 @@ #include #include #include +#include "dpu_hw_mdss.h" /** * Max hardware block count: For ex: max 12 SSPP pipes or @@ -182,6 +183,7 @@ enum { * @DPU_PINGPONG_TE2 Additional tear check block for split pipes * @DPU_PINGPONG_SPLIT PP block supports split fifo * @DPU_PINGPONG_SLAVE PP block is a suitable slave for split fifo + * @DPU_PINGPONG_DSC, Display stream compression blocks * @DPU_PINGPONG_DITHER, Dither blocks * @DPU_PINGPONG_MAX */ @@ -190,10 +192,32 @@ enum { DPU_PINGPONG_TE2, DPU_PINGPONG_SPLIT, DPU_PINGPONG_SLAVE, + DPU_PINGPONG_DSC, DPU_PINGPONG_DITHER, DPU_PINGPONG_MAX }; + +/** DSC sub-blocks/features + * @DPU_DSC_OUTPUT_CTRL Supports the control of the pp id which gets + * the pixel output from this DSC. + * @DPU_DSC_HW_REV_1_1 dsc block supports dsc 1.1 only + * @DPU_DSC_HW_REV_1_2 dsc block supports dsc 1.1 and 1.2 + * @DPU_DSC_NATIVE_422_EN, Supports native422 and native420 encoding + * @DPU_DSC_ENC, DSC encoder sub block + * @DPU_DSC_CTL, DSC ctl sub block + * @DPU_DSC_MAX + */ +enum { + DPU_DSC_OUTPUT_CTRL = 0x1, + DPU_DSC_HW_REV_1_1, + DPU_DSC_HW_REV_1_2, + DPU_DSC_NATIVE_422_EN, + DPU_DSC_ENC, + DPU_DSC_CTL, + DPU_DSC_MAX +}; + /** * CTL sub-blocks * @DPU_CTL_SPLIT_DISPLAY: CTL supports video mode split display @@ -276,15 +300,6 @@ enum { }; /** - * DSC features - * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets - * the pixel output from this DSC. - */ -enum { - DPU_DSC_OUTPUT_CTRL = 0x1, -}; - -/** * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU * @name: string name for debug purposes * @id: enum identifying this block @@ -346,6 +361,14 @@ struct dpu_pp_blk { }; /** + * struct dpu_dsc_blk : DSC Encoder sub-blk information + * @info: HW register and features supported by this sub-blk + */ +struct dpu_dsc_blk { + DPU_HW_SUBBLK_INFO; +}; + +/** * enum dpu_qos_lut_usage - define QoS LUT use cases */ enum dpu_qos_lut_usage { @@ -403,6 +426,7 @@ struct dpu_rotation_cfg { * @pixel_ram_size size of latency hiding and de-tiling buffer in bytes * @max_hdeci_exp max horizontal decimation supported (max is 2^value) * @max_vdeci_exp max vertical decimation supported (max is 2^value) + * @max_dsc_width max dsc line width support. */ struct dpu_caps { u32 max_mixer_width; @@ -419,6 +443,7 @@ struct dpu_caps { u32 pixel_ram_size; u32 max_hdeci_exp; u32 max_vdeci_exp; + u32 max_dsc_width; }; /** @@ -494,9 +519,20 @@ struct dpu_dspp_sub_blks { struct dpu_pingpong_sub_blks { struct dpu_pp_blk te; struct dpu_pp_blk te2; + struct dpu_pp_blk dsc; struct dpu_pp_blk dither; }; + +/** + * struct dpu_dsc_sub_blks : DSC sub-blks + * + */ +struct dpu_dsc_sub_blks { + struct dpu_dsc_blk enc; + struct dpu_dsc_blk ctl; +}; + /** * dpu_clk_ctrl_type - Defines top level clock control signals */ @@ -641,10 +677,14 @@ struct dpu_merge_3d_cfg { * struct dpu_dsc_cfg - information of DSC blocks * @id enum identifying this block * @base register offset of this block + * @len: length of hardware block * @features bit mask identifying sub-blocks/features + * @dsc_pair_mask: Bitmask of DSCs that can be controlled by same CTL */ struct dpu_dsc_cfg { DPU_HW_BLK_INFO; + DECLARE_BITMAP(dsc_pair_mask, DSC_MAX); + const struct dpu_dsc_sub_blks *sblk; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c index 619926d..51e8890 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2022, Linaro Limited + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved */ #include "dpu_kms.h" @@ -41,10 +42,11 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc) static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc, u32 mode, - u32 initial_lines) + u32 initial_lines, + bool ich_reset_override) { struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; - u32 data; + u32 data, lsb, bpp; u32 slice_last_group_size; u32 det_thresh_flatness; bool is_cmd_mode = !(mode & DSC_MODE_VIDEO); @@ -58,7 +60,14 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, data = (initial_lines << 20); data |= ((slice_last_group_size - 1) << 18); /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ - data |= (dsc->bits_per_pixel << 8); + data |= dsc->bits_per_pixel << 12; + lsb = dsc->bits_per_pixel % 4; + bpp = dsc->bits_per_pixel / 4; + bpp *= 4; + bpp <<= 4; + bpp |= lsb; + + data |= bpp << 8; data |= (dsc->block_pred_enable << 7); data |= (dsc->line_buf_depth << 3); data |= (dsc->simple_422 << 2); @@ -221,7 +230,13 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr, c->idx = idx; c->caps = cfg; - _setup_dsc_ops(&c->ops, c->caps->features); + + if (test_bit(DPU_DSC_HW_REV_1_1, &c->caps->features)) + _setup_dsc_ops(&c->ops, c->caps->features); + else if (test_bit(DPU_DSC_HW_REV_1_2, &c->caps->features)) + dpu_dsc_1_2_setup_ops(&c->ops, c->caps->features); + else + _setup_dsc_ops(&c->ops, c->caps->features); return c; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index ae9b5db..a48f572 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2020-2022, Linaro Limited */ +/* + * Copyright (c) 2020-2022, Linaro Limited + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved + */ #ifndef _DPU_HW_DSC_H #define _DPU_HW_DSC_H @@ -33,7 +36,8 @@ struct dpu_hw_dsc_ops { void (*dsc_config)(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc, u32 mode, - u32 initial_lines); + u32 initial_lines, + bool ich_reset_override); /** * dsc_config_thresh - programs panel thresholds @@ -43,6 +47,12 @@ struct dpu_hw_dsc_ops { void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc); + /** + * bind_pingpong_blk - enable/disable the connection with pp + * @hw_dsc: Pointer to dsc context + * @enable: enable/disable connection + * @pp: pingpong blk id + */ void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc, bool enable, enum dpu_pingpong pp); @@ -51,6 +61,7 @@ struct dpu_hw_dsc_ops { struct dpu_hw_dsc { struct dpu_hw_blk base; struct dpu_hw_blk_reg_map hw; + struct dpu_hw_ctl *hw_ctl; /* dsc */ enum dpu_dsc idx; @@ -76,9 +87,17 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr, */ void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc); +/** + * dpu_hw_dsc - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw) { return container_of(hw, struct dpu_hw_dsc, base); } +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops, + const unsigned long features); + #endif /* _DPU_HW_DSC_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c new file mode 100644 index 00000000..2be74ae --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved + */ + +#include "dpu_kms.h" +#include "dpu_hw_catalog.h" +#include "dpu_hwio.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_dsc.h" + + +#define DSC_CMN_MAIN_CNF 0x00 + +/* DPU_DSC_ENC register offsets */ +#define ENC_DF_CTRL 0x00 +#define ENC_GENERAL_STATUS 0x04 +#define ENC_HSLICE_STATUS 0x08 +#define ENC_OUT_STATUS 0x0C +#define ENC_INT_STAT 0x10 +#define ENC_INT_CLR 0x14 +#define ENC_INT_MASK 0x18 +#define DSC_MAIN_CONF 0x30 +#define DSC_PICTURE_SIZE 0x34 +#define DSC_SLICE_SIZE 0x38 +#define DSC_MISC_SIZE 0x3C +#define DSC_HRD_DELAYS 0x40 +#define DSC_RC_SCALE 0x44 +#define DSC_RC_SCALE_INC_DEC 0x48 +#define DSC_RC_OFFSETS_1 0x4C +#define DSC_RC_OFFSETS_2 0x50 +#define DSC_RC_OFFSETS_3 0x54 +#define DSC_RC_OFFSETS_4 0x58 +#define DSC_FLATNESS_QP 0x5C +#define DSC_RC_MODEL_SIZE 0x60 +#define DSC_RC_CONFIG 0x64 +#define DSC_RC_BUF_THRESH_0 0x68 +#define DSC_RC_BUF_THRESH_1 0x6C +#define DSC_RC_BUF_THRESH_2 0x70 +#define DSC_RC_BUF_THRESH_3 0x74 +#define DSC_RC_MIN_QP_0 0x78 +#define DSC_RC_MIN_QP_1 0x7C +#define DSC_RC_MIN_QP_2 0x80 +#define DSC_RC_MAX_QP_0 0x84 +#define DSC_RC_MAX_QP_1 0x88 +#define DSC_RC_MAX_QP_2 0x8C +#define DSC_RC_RANGE_BPG_OFFSETS_0 0x90 +#define DSC_RC_RANGE_BPG_OFFSETS_1 0x94 +#define DSC_RC_RANGE_BPG_OFFSETS_2 0x98 + +/* DPU_DSC_CTL register offsets */ +#define DSC_CTL 0x00 +#define DSC_CFG 0x04 +#define DSC_DATA_IN_SWAP 0x08 +#define DSC_CLK_CTRL 0x0C + + +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss) +{ + enum dpu_dsc idx; + + idx = hw_dsc->idx; + + if (!(hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))) { + if (num_ss == 1) + return 2399; + else if (num_ss == 2) + return 1199; + } else { + if (num_ss == 1) + return 1199; + else if (num_ss == 2) + return 599; + } + return 0; +} + +static inline int _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id, + u32 *idx) +{ + const struct dpu_dsc_sub_blks *sblk; + + if (!hw_dsc) + return -EINVAL; + + *idx = 0; + + sblk = hw_dsc->caps->sblk; + + switch (s_id) { + + case DPU_DSC_ENC: + *idx = sblk->enc.base; + break; + case DPU_DSC_CTL: + *idx = sblk->ctl.base; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc) +{ + struct dpu_hw_blk_reg_map *hw; + u32 idx; + + if (!hw_dsc) + return; + + if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx)) + return; + + hw = &hw_dsc->hw; + DPU_REG_WRITE(hw, DSC_CFG + idx, 0); + + if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx)) + return; + + DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, 0); + DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, 0); +} + +static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc, + struct drm_dsc_config *dsc, u32 mode, + u32 initial_lines, bool ich_reset_override) +{ + struct dpu_hw_blk_reg_map *hw; + struct msm_display_dsc_info *dsc_info; + u32 idx; + u32 data = 0; + u32 bpp; + void __iomem *off; + + if (!hw_dsc || !dsc) + return; + + hw = &hw_dsc->hw; + + dsc_info = to_msm_dsc_info(dsc); + + if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx)) + return; + + if (mode & DSC_MODE_SPLIT_PANEL) + data |= BIT(0); + + if (mode & DSC_MODE_MULTIPLEX) + data |= BIT(1); + + data |= (dsc_info->num_active_ss_per_enc & 0x3) << 7; + + DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data); + + data = (dsc_info->initial_lines & 0xff); + data |= ((mode & DSC_MODE_VIDEO) ? 1 : 0) << 9; + if (ich_reset_override) + data |= 0xC00; // set bit 10 and 11 + data |= (_dsc_calc_ob_max_addr(hw_dsc, dsc_info->num_active_ss_per_enc) << 18); + + DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, data); + + data = (dsc->dsc_version_minor & 0xf) << 28; + if (dsc->dsc_version_minor == 0x2) { + if (dsc->native_422) + data |= BIT(22); + if (dsc->native_420) + data |= BIT(21); + } + + bpp = dsc->bits_per_pixel; + /* as per hw requirement bpp should be programmed + * twice the actual value in case of 420 or 422 encoding + */ + if (dsc->native_422 || dsc->native_420) + bpp = 2 * bpp; + data |= (dsc->block_pred_enable ? 1 : 0) << 20; + data |= (bpp << 10); + data |= (dsc->line_buf_depth & 0xf) << 6; + data |= dsc->convert_rgb << 4; + data |= dsc->bits_per_component & 0xf; + + DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, data); + + data = (dsc->pic_width & 0xffff) | + ((dsc->pic_height & 0xffff) << 16); + + DPU_REG_WRITE(hw, DSC_PICTURE_SIZE + idx, data); + + data = (dsc->slice_width & 0xffff) | + ((dsc->slice_height & 0xffff) << 16); + + DPU_REG_WRITE(hw, DSC_SLICE_SIZE + idx, data); + + DPU_REG_WRITE(hw, DSC_MISC_SIZE + idx, + (dsc->slice_chunk_size) & 0xffff); + + data = (dsc->initial_xmit_delay & 0xffff) | + ((dsc->initial_dec_delay & 0xffff) << 16); + + DPU_REG_WRITE(hw, DSC_HRD_DELAYS + idx, data); + + DPU_REG_WRITE(hw, DSC_RC_SCALE + idx, + dsc->initial_scale_value & 0x3f); + + data = (dsc->scale_increment_interval & 0xffff) | + ((dsc->scale_decrement_interval & 0x7ff) << 16); + + DPU_REG_WRITE(hw, DSC_RC_SCALE_INC_DEC + idx, data); + + data = (dsc->first_line_bpg_offset & 0x1f) | + ((dsc->second_line_bpg_offset & 0x1f) << 5); + + DPU_REG_WRITE(hw, DSC_RC_OFFSETS_1 + idx, data); + + data = (dsc->nfl_bpg_offset & 0xffff) | + ((dsc->slice_bpg_offset & 0xffff) << 16); + + DPU_REG_WRITE(hw, DSC_RC_OFFSETS_2 + idx, data); + + data = (dsc->initial_offset & 0xffff) | + ((dsc->final_offset & 0xffff) << 16); + + DPU_REG_WRITE(hw, DSC_RC_OFFSETS_3 + idx, data); + + data = (dsc->nsl_bpg_offset & 0xffff) | + ((dsc->second_line_offset_adj & 0xffff) << 16); + + DPU_REG_WRITE(hw, DSC_RC_OFFSETS_4 + idx, data); + + data = (dsc->flatness_min_qp & 0x1f); + data |= (dsc->flatness_max_qp & 0x1f) << 5; + data |= (dsc_info->det_thresh_flatness & 0xff) << 10; + + DPU_REG_WRITE(hw, DSC_FLATNESS_QP + idx, data); + + DPU_REG_WRITE(hw, DSC_RC_MODEL_SIZE + idx, + (dsc->rc_model_size) & 0xffff); + + data = dsc->rc_edge_factor & 0xf; + data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8; + data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13; + data |= (dsc->rc_tgt_offset_high & 0xf) << 20; + data |= (dsc->rc_tgt_offset_low & 0xf) << 24; + + DPU_REG_WRITE(hw, DSC_RC_CONFIG + idx, data); + + /* program the dsc wrapper */ + if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx)) + return; + + off = hw->blk_addr + idx; + + data = BIT(0); /* encoder enable */ + if (dsc->native_422) + data |= BIT(8); + else if (dsc->native_420) + data |= BIT(9); + if (!dsc->convert_rgb) + data |= BIT(10); + if (dsc->bits_per_component == 8) + data |= BIT(11); + if (mode & DSC_MODE_SPLIT_PANEL) + data |= BIT(12); + if (mode & DSC_MODE_MULTIPLEX) + data |= BIT(13); + if (!(mode & DSC_MODE_VIDEO)) + data |= BIT(17); + + if (dsc_info->dsc_4hsmerge_en) { + data |= dsc_info->dsc_4hsmerge_padding << 18; + data |= dsc_info->dsc_4hsmerge_alignment << 22; + data |= BIT(16); + } + + DPU_REG_WRITE(hw, DSC_CFG + idx, data); + +// DPU_REG_WRITE(hw, DSC_DATA_IN_SWAP + idx, 0x14e5); +} + +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc, + struct drm_dsc_config *dsc) +{ + struct dpu_hw_blk_reg_map *hw; + struct msm_display_dsc_info *dsc_info; + u32 idx, off; + int i, j = 0; + struct drm_dsc_rc_range_parameters *rc; + u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0; + + if (!hw_dsc || !dsc) + return; + + if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx)) + return; + + hw = &hw_dsc->hw; + + dsc_info = to_msm_dsc_info(dsc); + + rc = dsc->rc_range_params; + + off = 0; + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) { + data |= dsc->rc_buf_thresh[i] << (8*j); + j++; + if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) { + DPU_REG_WRITE(hw, DSC_RC_BUF_THRESH_0 + idx + off, + data); + off += 4; + j = 0; + data = 0; + } + } + + off = 0; + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + min_qp |= (rc[i].range_min_qp & 0x1f) << 5*j; + max_qp |= (rc[i].range_max_qp & 0x1f) << 5*j; + bpg_off |= (rc[i].range_bpg_offset & 0x3f) << 6*j; + j++; + if (j == 5) { + DPU_REG_WRITE(hw, DSC_RC_MIN_QP_0 + idx + off, + min_qp); + DPU_REG_WRITE(hw, DSC_RC_MAX_QP_0 + idx + off, + max_qp); + DPU_REG_WRITE(hw, + DSC_RC_RANGE_BPG_OFFSETS_0 + idx + off, + bpg_off); + off += 4; + j = 0; + min_qp = 0; + max_qp = 0; + bpg_off = 0; + } + } +} + +static void dpu_hw_dsc_bind_pingpong_blk_1_2( + struct dpu_hw_dsc *hw_dsc, + bool enable, + const enum dpu_pingpong pp) +{ + struct dpu_hw_blk_reg_map *hw; + int idx; + int mux_cfg = 0xF; /* Disabled */ + + if (!hw_dsc) + return; + + if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx)) + return; + + hw = &hw_dsc->hw; + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0x7; + + DPU_REG_WRITE(hw, DSC_CTL + idx, mux_cfg); +} + +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops, + const unsigned long features) +{ + ops->dsc_disable = dpu_hw_dsc_disable_1_2; + ops->dsc_config = dpu_hw_dsc_config_1_2; + ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2; + ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; +} From patchwork Mon Jan 23 18:24:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112741 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D48BC38142 for ; Mon, 23 Jan 2023 18:25:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233932AbjAWSZv (ORCPT ); Mon, 23 Jan 2023 13:25:51 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233759AbjAWSZs (ORCPT ); Mon, 23 Jan 2023 13:25:48 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 618DE1E298; Mon, 23 Jan 2023 10:25:12 -0800 (PST) Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NFUVOH025345; Mon, 23 Jan 2023 18:25:06 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=uoBcwIUiXEq5X02y5wqlcnhiMx9It3eJGoPHPE8i1EM=; b=AVeeix96qQZvhXgztcT3yllRYQmx3/r8rGiH16EHLrN2y5/VAfa96u6jctSKHg+DcIyw B2zVyQLoQyEvxARrsbkdeG6o3s7nfZTwhnAHs03bEwa5Y+G831ITP4ldza835yKl+VTP kwYsAFh+sJO4YKbDroU40/0PJi1fWn/deTKQlW0iCYLpPN2x4imGDuMgmgzumVWBbpfy 1QmiSzBlpL+SlDbkm/fr0Xg50lrzsG7o3uGw1nUs8L78SFofrGOEkG+qW0hfLRDScR60 mWlA21dubODbH3q0M+6zmq4/73a1EEgBcdVAyrsFDHF74QJ7whbwD6Q/d6wssqiJbBht 8g== Received: from nalasppmta05.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89gtbhna-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:05 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA05.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIP4rU006458 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:05 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:25:04 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism Date: Mon, 23 Jan 2023 10:24:31 -0800 Message-ID: <1674498274-6010-12-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: 8gwiZ946bdC8T0IIYTupQDr8VBTpkG5K X-Proofpoint-ORIG-GUID: 8gwiZ946bdC8T0IIYTupQDr8VBTpkG5K X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 malwarescore=0 suspectscore=0 impostorscore=0 bulkscore=0 mlxlogscore=999 adultscore=0 priorityscore=1501 lowpriorityscore=0 spamscore=0 mlxscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org A new flushing mechanism is introduced to decouple peripheral metadata flushing from timing engine related flush. This patch add peripheral flushing functions. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 24 ++++++++++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 2 + .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 7 ++++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 43 ++++++++++++++++++++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 21 +++++++++++ 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 901e317..d2625b3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1472,6 +1472,12 @@ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, if (extra_flush_bits && ctl->ops.update_pending_flush) ctl->ops.update_pending_flush(ctl, extra_flush_bits); + if (phys->hw_intf->cap->type == INTF_DP && + phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC && + phys->comp_ratio) { + ctl->ops.update_pending_flush_periph(ctl, phys->hw_intf->idx); + } + ctl->ops.trigger_flush(ctl); if (ctl->ops.get_pending_flush) @@ -1814,12 +1820,18 @@ dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc, return DIV_ROUND_UP(total_pixels, dsc->slice_width); } -static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc, +static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc, + struct dpu_hw_dsc *hw_dsc, struct dpu_hw_pingpong *hw_pp, struct drm_dsc_config *dsc, u32 common_mode, u32 initial_lines) { + struct dpu_encoder_phys *cur_master = dpu_enc->cur_master; + struct dpu_hw_ctl *ctl; + + ctl = cur_master->hw_ctl; + if (hw_dsc->ops.dsc_config) hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false); @@ -1834,6 +1846,10 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc, if (hw_pp->ops.enable_dsc) hw_pp->ops.enable_dsc(hw_pp); + + if (ctl->ops.update_pending_flush_dsc) + ctl->ops.update_pending_flush_dsc(ctl, hw_dsc->idx); + } static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, @@ -1877,8 +1893,10 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, enc_ip_w = intf_ip_w / 2; initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w); - for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) - dpu_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], dsc, dsc_common_mode, initial_lines); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc, + dsc_common_mode, initial_lines); + } } void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 1d434b2..0569b36 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -200,6 +200,8 @@ struct dpu_encoder_phys { atomic_t pending_kickoff_cnt; wait_queue_head_t pending_kickoff_wq; int irq[INTR_IDX_MAX]; + enum msm_display_compression_type comp_type; + u32 comp_ratio; }; static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 48c4810..2d864f9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -427,6 +428,12 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) if (ctl->ops.update_pending_flush_merge_3d && phys_enc->hw_pp->merge_3d) ctl->ops.update_pending_flush_merge_3d(ctl, phys_enc->hw_pp->merge_3d->idx); + if (phys_enc->hw_intf->cap->type == INTF_DP && + phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC && + phys_enc->comp_ratio) { + ctl->ops.update_pending_flush_periph(ctl, phys_enc->hw_intf->idx); + } + skip_flush: DPU_DEBUG_VIDENC(phys_enc, "update pending flush ctl %d intf %d\n", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index b88a2f3..1891c57 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -33,6 +33,7 @@ #define CTL_DSC_FLUSH 0x104 #define CTL_WB_FLUSH 0x108 #define CTL_INTF_FLUSH 0x110 +#define CTL_PERIPH_FLUSH 0x128 #define CTL_INTF_MASTER 0x134 #define CTL_FETCH_PIPE_ACTIVE 0x0FC @@ -42,11 +43,13 @@ #define DPU_REG_RESET_TIMEOUT_US 2000 #define MERGE_3D_IDX 23 #define DSC_IDX 22 +#define PERIPH_IDX 30 #define INTF_IDX 31 #define WB_IDX 16 #define CTL_INVALID_BIT 0xffff #define CTL_DEFAULT_GROUP_ID 0xf + static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0, 1, 2, 3, CTL_INVALID_BIT, CTL_INVALID_BIT}; @@ -123,6 +126,7 @@ static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx, trace_dpu_hw_ctl_update_pending_flush(flushbits, ctx->pending_flush_mask); ctx->pending_flush_mask |= flushbits; + } static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) @@ -142,6 +146,15 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH, ctx->pending_wb_flush_mask); + if (ctx->pending_flush_mask & BIT(PERIPH_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH, + ctx->pending_periph_flush_mask); + + if (ctx->pending_flush_mask & BIT(DSC_IDX)) { + DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, + ctx->pending_dsc_flush_mask); + } + DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); } @@ -281,6 +294,13 @@ static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(INTF_IDX); } +static void dpu_hw_ctl_update_pending_flush_periph(struct dpu_hw_ctl *ctx, + enum dpu_intf intf) +{ + ctx->pending_periph_flush_mask |= BIT(intf - INTF_0); + ctx->pending_flush_mask |= BIT(PERIPH_IDX); +} + static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx, enum dpu_merge_3d merge_3d) { @@ -288,6 +308,13 @@ static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(MERGE_3D_IDX); } +static void dpu_hw_ctl_update_pending_flush_dsc_v1(struct dpu_hw_ctl *ctx, + enum dpu_dsc dsc_num) +{ + ctx->pending_dsc_flush_mask |= BIT(dsc_num - DSC_0); + ctx->pending_flush_mask |= BIT(DSC_IDX); +} + static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx, enum dpu_dspp dspp) { @@ -472,6 +499,7 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, u32 intf_active = 0; u32 wb_active = 0; u32 mode_sel = 0; + u32 dsc_active = 0; /* CTL_TOP[31:28] carries group_id to collate CTL paths * per VM. Explicitly disable it until VM support is @@ -502,9 +530,11 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, if (cfg->merge_3d) DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, BIT(cfg->merge_3d - MERGE_3D_0)); - if (cfg->dsc) { - DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, DSC_IDX); - DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc); + + if (cfg->dsc_num) { + dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE); + dsc_active |= BIT(cfg->dsc_num - DSC_0); + DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active); } } @@ -605,9 +635,16 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1; ops->update_pending_flush_intf = dpu_hw_ctl_update_pending_flush_intf_v1; + + ops->update_pending_flush_periph = + dpu_hw_ctl_update_pending_flush_periph; + ops->update_pending_flush_merge_3d = dpu_hw_ctl_update_pending_flush_merge_3d_v1; ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1; + + ops->update_pending_flush_dsc = + dpu_hw_ctl_update_pending_flush_dsc_v1; } else { ops->trigger_flush = dpu_hw_ctl_trigger_flush; ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 96c012e..d3faa0b1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -48,6 +48,7 @@ struct dpu_hw_intf_cfg { enum dpu_3d_blend_mode mode_3d; enum dpu_merge_3d merge_3d; enum dpu_ctl_mode_sel intf_mode_sel; + enum dpu_dsc dsc_num; int stream_sel; unsigned int dsc; }; @@ -121,6 +122,15 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** + * OR in the given flushbits to the cached pending_(periph_)flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @blk : interface block index + */ + void (*update_pending_flush_periph)(struct dpu_hw_ctl *ctx, + enum dpu_intf blk); + + /** * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask * No effect on hardware * @ctx : ctl path ctx pointer @@ -156,6 +166,15 @@ struct dpu_hw_ctl_ops { void (*update_pending_flush_dspp)(struct dpu_hw_ctl *ctx, enum dpu_dspp blk); /** + * OR in the given flushbits to the cached pending_(dsc_)flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @blk : interface block index + */ + void (*update_pending_flush_dsc)(struct dpu_hw_ctl *ctx, + enum dpu_dsc blk); + + /** * Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer */ @@ -241,7 +260,9 @@ struct dpu_hw_ctl { u32 pending_flush_mask; u32 pending_intf_flush_mask; u32 pending_wb_flush_mask; + u32 pending_periph_flush_mask; u32 pending_merge_3d_flush_mask; + u32 pending_dsc_flush_mask; /* ops */ struct dpu_hw_ctl_ops ops; From patchwork Mon Jan 23 18:24:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112743 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C77EC38142 for ; Mon, 23 Jan 2023 18:25:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233903AbjAWSZ5 (ORCPT ); Mon, 23 Jan 2023 13:25:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232054AbjAWSZt (ORCPT ); Mon, 23 Jan 2023 13:25:49 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E3D453253B; Mon, 23 Jan 2023 10:25:13 -0800 (PST) Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NHlP0E000963; Mon, 23 Jan 2023 18:25:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=wvGH7/Rlwu45QOGwJN13yXrhRNE0SHq+W0b9xLXNsQs=; b=m0XBfHv7USXGDogxjmHHFwyzbGFNalDyXPtOhbcQjffrtqzEmWJHWO/DRbTGhMCVlHvX UV693DpfdQ5HDZh383hZdsTesyd825KaW9HXLyfuTUuylpv+hcjtQE+T9aSMlIChYLcF zCc4LpAU2I1DWJk4R5EpwFo+mkixQtTC4JWvPSCOWW0NsQINOpwI2P2D0eWks+5NB3t2 23M5FOzPJ9RLKklraFW9Naa4G9IpXMDIB+wFGwmZr3vXrTzKEDV/FJv9qJbHB/cuUr5p l++ctGHAtQquCsF/6227WBfy89OaHuMY+AfQprrh2S4wHR03mBrp9o6rBUCWUqj/d3w0 SA== Received: from nalasppmta05.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89f5bjwu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:07 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA05.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIP6wZ006672 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:06 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:25:05 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC Date: Mon, 23 Jan 2023 10:24:32 -0800 Message-ID: <1674498274-6010-13-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: lS_pj5WykZ6oueGJ-WRvafge6-UlJhoW X-Proofpoint-GUID: lS_pj5WykZ6oueGJ-WRvafge6-UlJhoW X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 bulkscore=0 clxscore=1015 mlxscore=0 spamscore=0 phishscore=0 adultscore=0 lowpriorityscore=0 suspectscore=0 malwarescore=0 priorityscore=1501 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230176 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Current implementation timing engine programming does not consider compression factors. This patch add consideration of DSC factors while programming timing engine. Signed-off-by: Kuogee Hsieh --- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 14 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 132 +++++++++++++-------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 10 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h | 6 +- 5 files changed, 110 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 2d864f9..3330e185 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -279,6 +279,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine( if (phys_enc->hw_pp->merge_3d) intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx; + phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev; + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &timing_params, fmt); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 7b0b092..c6ee789 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -43,16 +43,22 @@ #define DPU_HW_VER_500 DPU_HW_VER(5, 0, 0) /* sm8150 v1.0 */ #define DPU_HW_VER_501 DPU_HW_VER(5, 0, 1) /* sm8150 v2.0 */ #define DPU_HW_VER_510 DPU_HW_VER(5, 1, 1) /* sc8180 */ -#define DPU_HW_VER_600 DPU_HW_VER(6, 0, 0) /* sm8250 */ +#define DPU_HW_VER_600 DPU_HW_VER(6, 0, 0) /* sm8250, kona */ #define DPU_HW_VER_620 DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */ #define DPU_HW_VER_630 DPU_HW_VER(6, 3, 0) /* sm6115|sm4250 */ #define DPU_HW_VER_650 DPU_HW_VER(6, 5, 0) /* qcm2290|sm4125 */ -#define DPU_HW_VER_700 DPU_HW_VER(7, 0, 0) /* sm8350 */ +#define DPU_HW_VER_700 DPU_HW_VER(7, 0, 0) /* sm8350, lahaina */ #define DPU_HW_VER_720 DPU_HW_VER(7, 2, 0) /* sc7280 */ #define DPU_HW_VER_800 DPU_HW_VER(8, 0, 0) /* sc8280xp */ -#define DPU_HW_VER_810 DPU_HW_VER(8, 1, 0) /* sm8450 */ +#define DPU_HW_VER_810 DPU_HW_VER(8, 1, 0) /* sm8450, waipio */ #define DPU_HW_VER_900 DPU_HW_VER(9, 0, 0) /* sm8550 */ +/* Avoid using below IS_XXX macros outside catalog, use feature bit instead */ +#define IS_DPU_MAJOR_SAME(rev1, rev2) \ + (DPU_HW_MAJOR((rev1)) == DPU_HW_MAJOR((rev2))) +#define IS_DPU_MAJOR_MINOR_SAME(rev1, rev2) \ + (DPU_HW_MAJOR_MINOR((rev1)) == DPU_HW_MAJOR_MINOR((rev2))) + #define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170) #define IS_MSM8998_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_300) #define IS_SDM845_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_400) @@ -240,6 +246,7 @@ enum { * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which * pixel data arrives to this INTF * @DPU_INTF_TE INTF block has TE configuration support + * @DPU_INTF_TE_ALIGN_VSYNC INTF block has POMS Align vsync support * @DPU_DATA_HCTL_EN Allows data to be transferred at different rate than video timing * @DPU_INTF_MAX @@ -247,6 +254,7 @@ enum { enum { DPU_INTF_INPUT_CTRL = 0x1, DPU_INTF_TE, + DPU_INTF_TE_ALIGN_VSYNC, DPU_DATA_HCTL_EN, DPU_INTF_MAX }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index 7ce66bf..238efdb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ @@ -44,6 +44,7 @@ #define INTF_DEFLICKER_STRNG_COEFF 0x0F4 #define INTF_DEFLICKER_WEAK_COEFF 0x0F8 +#define INTF_REG_SPLIT_LINK 0x080 #define INTF_DSI_CMD_MODE_TRIGGER_EN 0x084 #define INTF_PANEL_FORMAT 0x090 #define INTF_TPG_ENABLE 0x100 @@ -65,9 +66,9 @@ #define INTF_CFG_ACTIVE_H_EN BIT(29) #define INTF_CFG_ACTIVE_V_EN BIT(30) - #define INTF_CFG2_DATABUS_WIDEN BIT(0) #define INTF_CFG2_DATA_HCTL_EN BIT(4) +#define INTF_CFG2_ALIGN_VSYNC_TO_TE BIT(16) #define INTF_MISR_CTRL 0x180 #define INTF_MISR_SIGNATURE 0x184 @@ -91,6 +92,16 @@ static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf, return ERR_PTR(-EINVAL); } +static inline void _check_and_set_comp_bit(struct dpu_hw_intf *ctx, + bool dsc_4hs_merge, bool compression_en, u32 *intf_cfg2) +{ + if (((DPU_HW_MAJOR(ctx->hw_rev) >= DPU_HW_MAJOR(DPU_HW_VER_700)) && compression_en) + || (IS_DPU_MAJOR_SAME(ctx->hw_rev, DPU_HW_VER_600) && dsc_4hs_merge)) + (*intf_cfg2) |= BIT(12); + else if (!compression_en) + (*intf_cfg2) &= ~BIT(12); +} + static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, const struct intf_timing_params *p, const struct dpu_format *fmt) @@ -113,82 +124,96 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, /* read interface_cfg */ intf_cfg = DPU_REG_READ(c, INTF_CONFIG); - if (ctx->cap->type == INTF_DP) + if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP) dp_intf = true; hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + - p->h_front_porch; + p->h_front_porch; vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + - p->v_front_porch; + p->v_front_porch; display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * - hsync_period) + p->hsync_skew; + hsync_period) + p->hsync_skew; display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + - p->hsync_skew - 1; + p->hsync_skew - 1; + + hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; hsync_start_x = p->h_back_porch + p->hsync_pulse_width; hsync_end_x = hsync_period - p->h_front_porch - 1; - if (p->width != p->xres) { /* border fill added */ - active_h_start = hsync_start_x; - active_h_end = active_h_start + p->xres - 1; - } else { - active_h_start = 0; - active_h_end = 0; - } - - if (p->height != p->yres) { /* border fill added */ - active_v_start = display_v_start; - active_v_end = active_v_start + (p->yres * hsync_period) - 1; - } else { - active_v_start = 0; - active_v_end = 0; - } - - if (active_h_end) { - active_hctl = (active_h_end << 16) | active_h_start; - intf_cfg |= INTF_CFG_ACTIVE_H_EN; - } else { - active_hctl = 0; - } - - if (active_v_end) - intf_cfg |= INTF_CFG_ACTIVE_V_EN; - - hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; - display_hctl = (hsync_end_x << 16) | hsync_start_x; - /* * DATA_HCTL_EN controls data timing which can be different from * video timing. It is recommended to enable it for all cases, except * if compression is enabled in 1 pixel per clock mode */ + if (!p->compression_en || p->wide_bus_en) + intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN; + if (p->wide_bus_en) - intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN; + intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN; + /* + * If widebus is disabled: + * For uncompressed stream, the data is valid for the entire active + * window period. + * For compressed stream, data is valid for a shorter time period + * inside the active window depending on the compression ratio. + * + * If widebus is enabled: + * For uncompressed stream, data is valid for only half the active + * window, since the data rate is doubled in this mode. + * p->width holds the adjusted width for DP but unadjusted width for DSI + * For compressed stream, data validity window needs to be adjusted for + * compression ratio and then further halved. + */ data_width = p->width; + if (p->compression_en) { + if (p->wide_bus_en) + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6); + else + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3); + } else if (!dp_intf && p->wide_bus_en) { + data_width = p->width >> 1; + } else { + data_width = p->width; + } + hsync_data_start_x = hsync_start_x; hsync_data_end_x = hsync_start_x + data_width - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x; if (dp_intf) { /* DP timing adjustment */ display_v_start += p->hsync_pulse_width + p->h_back_porch; display_v_end -= p->h_front_porch; + } + + intf_cfg |= INTF_CFG_ACTIVE_H_EN; + intf_cfg |= INTF_CFG_ACTIVE_V_EN; + active_h_start = hsync_start_x; + active_h_end = active_h_start + p->xres - 1; + active_v_start = display_v_start; + active_v_end = active_v_start + (p->yres * hsync_period) - 1; - active_h_start = hsync_start_x; - active_h_end = active_h_start + p->xres - 1; - active_v_start = display_v_start; - active_v_end = active_v_start + (p->yres * hsync_period) - 1; + active_hctl = (active_h_end << 16) | active_h_start; - active_hctl = (active_h_end << 16) | active_h_start; + if (dp_intf) { display_hctl = active_hctl; - intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN; + if (p->compression_en) { + active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16; + active_data_hctl += hsync_start_x; + + display_data_hctl = active_data_hctl; + } } + _check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en, &intf_cfg2); + den_polarity = 0; if (ctx->cap->type == INTF_HDMI) { hsync_polarity = p->yres >= 720 ? 0 : 1; @@ -202,7 +227,7 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, } polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ (vsync_polarity << 1) | /* VSYNC Polarity */ - (hsync_polarity << 0); /* HSYNC Polarity */ + (hsync_polarity << 0); /* HSYNC Polarity */ if (!DPU_FORMAT_IS_YUV(fmt)) panel_format = (fmt->bits[C0_G_Y] | @@ -216,6 +241,17 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, (COLOR_8BIT << 4) | (0x21 << 8)); + if (p->wide_bus_en) + intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN; + + /* Synchronize timing engine enable to TE */ + if ((ctx->cap->features & BIT(DPU_INTF_TE_ALIGN_VSYNC)) + && p->poms_align_vsync) + intf_cfg2 |= INTF_CFG2_ALIGN_VSYNC_TO_TE; + + if (ctx->cfg.split_link_en) + DPU_REG_WRITE(c, INTF_REG_SPLIT_LINK, 0x3); + DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl); DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0, @@ -233,11 +269,9 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3); DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg); DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); - if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) { - DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); - DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl); - DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl); - } + DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); + DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl); + DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl); } static void dpu_hw_intf_enable_timing_engine( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index 643dd10..57be86d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ @@ -10,6 +10,7 @@ #include "dpu_hw_catalog.h" #include "dpu_hw_mdss.h" #include "dpu_hw_util.h" +#include "dpu_hw_top.h" struct dpu_hw_intf; @@ -33,6 +34,11 @@ struct intf_timing_params { u32 hsync_skew; bool wide_bus_en; + bool compression_en; + u32 extra_dto_cycles; /* for DP only */ + bool dsc_4hs_merge; /* DSC 4HS merge */ + bool poms_align_vsync; /* poms with vsync aligned */ + u32 dce_bytes_per_line; }; struct intf_prog_fetch { @@ -86,11 +92,13 @@ struct dpu_hw_intf_ops { struct dpu_hw_intf { struct dpu_hw_blk_reg_map hw; + u32 hw_rev; /* mdss hw_rev */ /* intf */ enum dpu_intf idx; const struct dpu_intf_cfg *cap; const struct dpu_mdss_cfg *mdss; + struct split_pipe_cfg cfg; /* ops */ struct dpu_hw_intf_ops ops; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index a1a9e44..1212fa2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DPU_HW_TOP_H @@ -34,12 +36,14 @@ struct traffic_shaper_cfg { * @intf : Interface id for main control path * @split_flush_en: Allows both the paths to be flushed when master path is * flushed + * @split_link_en: Check if split link is enabled */ struct split_pipe_cfg { bool en; enum dpu_intf_mode mode; enum dpu_intf intf; bool split_flush_en; + bool split_link_en; }; /** From patchwork Mon Jan 23 18:24:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112745 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3261C05027 for ; Mon, 23 Jan 2023 18:26:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233557AbjAWS0P (ORCPT ); Mon, 23 Jan 2023 13:26:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37472 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232865AbjAWSZu (ORCPT ); Mon, 23 Jan 2023 13:25:50 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CE40432E69; Mon, 23 Jan 2023 10:25:16 -0800 (PST) Received: from pps.filterd (m0279865.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NESboY021523; Mon, 23 Jan 2023 18:25:09 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=LCkNhE5YReZZLDM45+VvJIjTTt6jg624wFRIsYsBBgM=; b=Z0vyeK4ef50GqgIxQ7MwhJtMJuMEyeZuzKo7+oyNZ2v0AlbBav88aEL3ENgn4fX0AzVy NozabcPbttY6VIrFgYc5a2HJ3u5ESbOOap5hGjYRbCdf2wwt57/Q8VayRWZqz+yNhU+K kfBjfkUpJ2UuAnnLaukGTRt08eSqjk3ADiXkbzQxBmixxFmNOykJ06iKz5S+nB3Pzw1l ntxFgauRyZk2CGIxGszYUSUVVpomFTtbdU4r/9cauX2Z7t45S5jSDa3FUcnRnd3eV8wE WrqvU0RS7NLVjNYidQH6vtGUS8gsCxOMydsnDcKMiUXebQNckzil2sFJNi1eSXG9fxHP CQ== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89htuhkx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:09 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIP81Z003617 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:08 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:25:07 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder Date: Mon, 23 Jan 2023 10:24:33 -0800 Message-ID: <1674498274-6010-14-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: BF8xfKjsi7WR6QMxdogYlQxQsJI_suFC X-Proofpoint-GUID: BF8xfKjsi7WR6QMxdogYlQxQsJI_suFC X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 lowpriorityscore=0 mlxscore=0 malwarescore=0 bulkscore=0 impostorscore=0 mlxlogscore=999 suspectscore=0 clxscore=1015 phishscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Since display Port is an external peripheral, runtime compression detection is added to handle plug in and unplugged events. Currently only DSC compression supported. Once DSC compression detected, topology is static added and used to allocate system resources to accommodate DSC requirement. DSC related parameters are calculated and committed to DSC encoder. Also compression information are propagated to phy and committed to timing engine at video mode. This patch completes DSC implementation. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 314 ++++++++++++++++----- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 5 +- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 34 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h | 3 + drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 10 +- 5 files changed, 292 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index d2625b3..d7f5f93 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "msm_drv.h" #include "dpu_kms.h" @@ -30,6 +31,7 @@ #include "dpu_crtc.h" #include "dpu_trace.h" #include "dpu_core_irq.h" +#include "dpu_dsc_helper.h" #include "disp/msm_disp_snapshot.h" #define DPU_DEBUG_ENC(e, fmt, ...) DRM_DEBUG_ATOMIC("enc%d " fmt,\ @@ -542,12 +544,12 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc) return (num_dsc > 0) && (num_dsc > intf_count); } -static struct msm_display_topology dpu_encoder_get_topology( +static void dpu_encoder_get_topology( struct dpu_encoder_virt *dpu_enc, struct dpu_kms *dpu_kms, - struct drm_display_mode *mode) + struct drm_display_mode *mode, + struct msm_display_topology *topology) { - struct msm_display_topology topology = {0}; int i, intf_count = 0; for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) @@ -567,19 +569,19 @@ static struct msm_display_topology dpu_encoder_get_topology( * sufficient number */ if (intf_count == 2) - topology.num_lm = 2; + topology->num_lm = 2; else if (!dpu_kms->catalog->caps->has_3d_merge) - topology.num_lm = 1; + topology->num_lm = 1; else - topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; + topology->num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) { if (dpu_kms->catalog->dspp && - (dpu_kms->catalog->dspp_count >= topology.num_lm)) - topology.num_dspp = topology.num_lm; + (dpu_kms->catalog->dspp_count >= topology->num_lm)) + topology->num_dspp = topology->num_lm; } - topology.num_intf = intf_count; + topology->num_intf = intf_count; if (dpu_enc->dsc) { /* @@ -588,12 +590,31 @@ static struct msm_display_topology dpu_encoder_get_topology( * this is power optimal and can drive up to (including) 4k * screens */ - topology.num_dsc = 2; - topology.num_lm = 2; - topology.num_intf = 1; + topology->num_dsc = 2; + topology->num_intf = 1; + topology->num_lm = 2; } - return topology; + /* + * default topology for display port DSC implementation. + * TODO: + * change to runtime resource calculation + */ + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) { + topology->num_dsc = 0; + topology->num_intf = intf_count; + + if (dpu_enc->comp_info) { + /* In case of Display Stream Compression (DSC), we would use + * 2 encoders, 2 layer mixers and 1 interface + * this is power optimal and can drive up to (including) 4k + * screens + */ + topology->num_dsc = 1; + topology->num_intf = 1; + topology->num_lm = 1; + } + } } static int dpu_encoder_virt_atomic_check( @@ -605,7 +626,7 @@ static int dpu_encoder_virt_atomic_check( struct msm_drm_private *priv; struct dpu_kms *dpu_kms; struct drm_display_mode *adj_mode; - struct msm_display_topology topology; + struct msm_display_topology *topology; struct dpu_global_state *global_state; int i = 0; int ret = 0; @@ -642,7 +663,27 @@ static int dpu_encoder_virt_atomic_check( } } - topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); + /* + * For display port, at this moment we know panel had been plugged in + * and dsc supported is detected. + * however we do not know the details of resolution will be used + * until mode_set had been done. + * + * use default topology to reserve system resource for dsc + * + * TODO: run time calculation of topology instead of hardcode it now + */ + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) { + struct drm_bridge *bridge; + + if (!dpu_enc->comp_info) { + bridge = drm_bridge_chain_get_first_bridge(drm_enc); + dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge); + } + } + + topology = &dpu_enc->topology; + dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, topology); /* Reserve dynamic resources now. */ if (!ret) { @@ -655,7 +696,7 @@ static int dpu_encoder_virt_atomic_check( if (!crtc_state->active_changed || crtc_state->active) ret = dpu_rm_reserve(&dpu_kms->rm, global_state, - drm_enc, crtc_state, topology); + drm_enc, crtc_state, *topology); } } @@ -1009,7 +1050,37 @@ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc, if (phys->ops.cleanup_wb_job) phys->ops.cleanup_wb_job(phys, job); + } +} + +static void dpu_encoder_populate_encoder_phys(struct drm_encoder *drm_enc, + struct dpu_encoder_virt *dpu_enc) +{ + struct msm_compression_info *comp_info; + struct msm_display_dsc_info *dsc_info; + int i; + + if (!dpu_enc->comp_info) + return; + + comp_info = dpu_enc->comp_info; + dsc_info = &comp_info->msm_dsc_info; + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys) + continue; + + phys->comp_type = comp_info->comp_type; + phys->comp_ratio = comp_info->comp_ratio; + if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) { + phys->dsc_extra_pclk_cycle_cnt = dsc_info->pclk_per_line; + phys->dsc_extra_disp_width = dsc_info->extra_width; + phys->dce_bytes_per_line = + dsc_info->bytes_per_pkt * dsc_info->pkt_per_line; + } } } @@ -1050,6 +1121,24 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, trace_dpu_enc_mode_set(DRMID(drm_enc)); + /* + * For display port, msm_dp_bridge_mode_set() will conver panel info + * into dp_mode. This including detail dsc information if it is enabled. + * after that, msm_dp_bridge_get_compression() will return detail + * dsc compression info + */ + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) { + struct drm_display_mode *mode, *adjusted_mode; + struct drm_bridge *bridge; + + mode = &crtc_state->mode; + adjusted_mode = &crtc_state->adjusted_mode; + bridge = drm_bridge_chain_get_first_bridge(drm_enc); + msm_dp_bridge_mode_set(bridge, mode, adjusted_mode); + + dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge); + } + /* Query resource that have been reserved in atomic check step. */ num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, drm_enc->base.id, DPU_HW_BLK_PINGPONG, hw_pp, @@ -1061,19 +1150,18 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp, ARRAY_SIZE(hw_dspp)); + num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_DSC, + hw_dsc, ARRAY_SIZE(hw_dsc)); for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i]) : NULL; - if (dpu_enc->dsc) { - num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, - drm_enc->base.id, DPU_HW_BLK_DSC, - hw_dsc, ARRAY_SIZE(hw_dsc)); - for (i = 0; i < num_dsc; i++) { - dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]); - dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0); - } + for (i = 0; i < num_dsc; i++) { + dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]); + dpu_enc->hw_pp[i]->dsc = dpu_enc->hw_dsc[i]; /* bind dsc to pp */ + dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0); } dpu_enc->dsc_mask = dsc_mask; @@ -1110,10 +1198,22 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, phys->hw_pp = dpu_enc->hw_pp[i]; phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]); + if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX) + phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx); + + /* phys->hw_intf populated at dpu_encoder_setup_display() */ + if (!phys->hw_intf) { + DPU_ERROR_ENC(dpu_enc, + "no intf block assigned at idx: %d\n", i); + return; + } + phys->cached_mode = crtc_state->adjusted_mode; if (phys->ops.atomic_mode_set) phys->ops.atomic_mode_set(phys, crtc_state, conn_state); } + + dpu_encoder_populate_encoder_phys(drm_enc, dpu_enc); } static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) @@ -1208,6 +1308,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) mutex_unlock(&dpu_enc->enc_lock); } +static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc); + static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = NULL; @@ -1233,6 +1335,10 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) phys->ops.disable(phys); } + if (dpu_enc->comp_info && (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS)) { + dpu_encoder_unprep_dsc(dpu_enc); + dpu_enc->comp_info = NULL; + } /* after phys waits for frame-done, should be no more frames pending */ if (atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) { @@ -1795,40 +1901,16 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) nsecs_to_jiffies(ktime_to_ns(wakeup_time))); } -static u32 -dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc, - u32 enc_ip_width) -{ - int ssm_delay, total_pixels, soft_slice_per_enc; - - soft_slice_per_enc = enc_ip_width / dsc->slice_width; - - /* - * minimum number of initial line pixels is a sum of: - * 1. sub-stream multiplexer delay (83 groups for 8bpc, - * 91 for 10 bpc) * 3 - * 2. for two soft slice cases, add extra sub-stream multiplexer * 3 - * 3. the initial xmit delay - * 4. total pipeline delay through the "lock step" of encoder (47) - * 5. 6 additional pixels as the output of the rate buffer is - * 48 bits wide - */ - ssm_delay = ((dsc->bits_per_component < 10) ? 84 : 92); - total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47; - if (soft_slice_per_enc > 1) - total_pixels += (ssm_delay * 3); - return DIV_ROUND_UP(total_pixels, dsc->slice_width); -} - static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc, struct dpu_hw_dsc *hw_dsc, struct dpu_hw_pingpong *hw_pp, - struct drm_dsc_config *dsc, + struct msm_display_dsc_info *dsc_info, u32 common_mode, u32 initial_lines) { struct dpu_encoder_phys *cur_master = dpu_enc->cur_master; struct dpu_hw_ctl *ctl; + struct drm_dsc_config *dsc = &dsc_info->drm_dsc; ctl = cur_master->hw_ctl; @@ -1852,51 +1934,137 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc, } +static void dpu_encoder_dsc_disable(struct dpu_encoder_virt *dpu_enc, + struct dpu_hw_dsc *hw_dsc, + struct dpu_hw_pingpong *hw_pp) +{ + struct dpu_encoder_phys *cur_master = dpu_enc->cur_master; + struct dpu_hw_ctl *ctl; + + ctl = cur_master->hw_ctl; + + if (hw_dsc->ops.dsc_disable) + hw_dsc->ops.dsc_disable(hw_dsc); + + if (hw_pp->ops.disable_dsc) + hw_pp->ops.disable_dsc(hw_pp); + +} + static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, - struct drm_dsc_config *dsc) + struct msm_display_dsc_info *dsc_info) { /* coding only for 2LM, 2enc, 1 dsc config */ struct dpu_encoder_phys *enc_master = dpu_enc->cur_master; struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct msm_display_topology *topology = &dpu_enc->topology; + enum dpu_3d_blend_mode mode_3d; int this_frame_slices; int intf_ip_w, enc_ip_w; - int dsc_common_mode; - int pic_width; - u32 initial_lines; + int dsc_common_mode = 0; + int dsc_pic_width; + int num_lm, num_dsc, num_intf; + bool dsc_merge, merge_3d, dsc_4hsmerge; + bool disable_merge_3d = false; + int ich_res; int i; for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { hw_pp[i] = dpu_enc->hw_pp[i]; hw_dsc[i] = dpu_enc->hw_dsc[i]; + } - if (!hw_pp[i] || !hw_dsc[i]) { - DPU_ERROR_ENC(dpu_enc, "invalid params for DSC\n"); - return; - } + num_lm = topology->num_lm; + num_dsc = topology->num_dsc; + num_intf = topology->num_intf; + + + mode_3d = (num_lm > num_dsc) ? BLEND_3D_H_ROW_INT : BLEND_3D_NONE; + merge_3d = ((mode_3d != BLEND_3D_NONE) && !(enc_master->hw_intf->cfg.split_link_en)) ? + true : false; + + dsc_merge = ((num_dsc > num_intf) && !dsc_info->half_panel_pu && + !(enc_master->hw_intf->cfg.split_link_en)) ? true : false; + disable_merge_3d = (merge_3d && dsc_info->half_panel_pu) ? false : true; + dsc_4hsmerge = (dsc_merge && num_dsc == 4 && num_intf == 1) ? true : false; + + /* + * If this encoder is driving more than one DSC encoder, they + * operate in tandem, same pic dimension needs to be used by + * each of them.(pp-split is assumed to be not supported) + * + * If encoder is driving more than 2 DSCs, each DSC pair will operate + * on half of the picture in tandem. + */ + dsc_pic_width = dsc_info->drm_dsc.pic_width; + + if (num_dsc > 2) { + dsc_pic_width /= 2; + dsc_info->dsc_4hsmerge_en = dsc_4hsmerge; } - dsc_common_mode = 0; - pic_width = dsc->pic_width; + this_frame_slices = dsc_pic_width / dsc_info->drm_dsc.slice_width; + intf_ip_w = this_frame_slices * dsc_info->drm_dsc.slice_width; + enc_ip_w = intf_ip_w; + + if (!dsc_info->half_panel_pu) + intf_ip_w /= num_intf; + if (!dsc_info->half_panel_pu && (num_dsc > 1)) + dsc_common_mode |= DSC_MODE_SPLIT_PANEL; + if (dsc_merge) { + dsc_common_mode |= DSC_MODE_MULTIPLEX; + /* + * in dsc merge case: when using 2 encoders for the same + * stream, no. of slices need to be same on both the + * encoders. + */ + enc_ip_w = intf_ip_w / 2; + } - dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL; if (enc_master->intf_mode == INTF_MODE_VIDEO) dsc_common_mode |= DSC_MODE_VIDEO; - this_frame_slices = pic_width / dsc->slice_width; - intf_ip_w = this_frame_slices * dsc->slice_width; + dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count; + + if (dsc_info->dsc_4hsmerge_en) + dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 2; + else if ((dsc_common_mode & DSC_MODE_MULTIPLEX) || (dsc_info->half_panel_pu)) + dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 1; + + dpu_dsc_populate_dsc_private_params(dsc_info, intf_ip_w); + + dpu_dsc_initial_line_calc(dsc_info, enc_ip_w, dsc_common_mode); /* * dsc merge case: when using 2 encoders for the same stream, * no. of slices need to be same on both the encoders. */ - enc_ip_w = intf_ip_w / 2; - initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w); + ich_res = dpu_dsc_ich_reset_override_needed(dsc_info->half_panel_pu, dsc_info); + + for (i = 0; i < num_dsc; i++) { + dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc_info, + dsc_common_mode, 0); + } +} + +static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc) +{ + /* coding only for 2LM, 2enc, 1 dsc config */ + struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct msm_display_topology *topology = &dpu_enc->topology; + int i, num_dsc; for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { - dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc, - dsc_common_mode, initial_lines); + hw_pp[i] = dpu_enc->hw_pp[i]; + hw_dsc[i] = dpu_enc->hw_dsc[i]; } + + num_dsc = topology->num_dsc; + + for (i = 0; i < num_dsc; i++) + dpu_encoder_dsc_disable(dpu_enc, hw_dsc[i], hw_pp[i]); } void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) @@ -1904,6 +2072,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; bool needs_hw_reset = false; + bool needs_phy_enable = false; unsigned int i; dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -1918,6 +2087,9 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) phys->ops.prepare_for_kickoff(phys); if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) needs_hw_reset = true; + + if (phys->enable_state == DPU_ENC_ENABLING) + needs_phy_enable = true; } DPU_ATRACE_END("enc_prepare_for_kickoff"); @@ -1931,8 +2103,10 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) } } - if (dpu_enc->dsc) - dpu_encoder_prep_dsc(dpu_enc, dpu_enc->dsc); + if (needs_phy_enable && dpu_enc->comp_info) + dpu_encoder_prep_dsc(dpu_enc, &dpu_enc->comp_info->msm_dsc_info); + + } bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc) @@ -2295,7 +2469,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, dpu_kms->catalog->caps->has_idle_pc; dpu_enc->comp_info = disp_info->comp_info; - if (dpu_enc->comp_info) + if (dpu_enc->comp_info && dpu_enc->comp_info->enabled) dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc; mutex_lock(&dpu_enc->enc_lock); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 0569b36..ae4f6a8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. */ @@ -202,6 +202,9 @@ struct dpu_encoder_phys { int irq[INTR_IDX_MAX]; enum msm_display_compression_type comp_type; u32 comp_ratio; + u32 dsc_extra_pclk_cycle_cnt; + u32 dsc_extra_disp_width; + u32 dce_bytes_per_line; }; static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 3330e185..6c7d791 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -86,6 +86,11 @@ static void drm_mode_to_intf_timing_params( timing->underflow_clr = 0xff; timing->hsync_skew = mode->hskew; + if (phys_enc->comp_type != MSM_DISPLAY_COMPRESSION_NONE) { + timing->compression_en = true; + timing->dce_bytes_per_line = phys_enc->dce_bytes_per_line; + } + /* DSI controller cannot handle active-low sync signals. */ if (phys_enc->hw_intf->cap->type == INTF_DSI) { timing->hsync_polarity = 0; @@ -104,14 +109,36 @@ static void drm_mode_to_intf_timing_params( /* * for DP, divide the horizonal parameters by 2 when - * widebus is enabled + * widebus or compression is enabled, irrespective of + * compression ratio */ - if (phys_enc->hw_intf->cap->type == INTF_DP && timing->wide_bus_en) { + if (phys_enc->hw_intf->cap->type == INTF_DP && + (timing->wide_bus_en || (phys_enc->comp_ratio > 1))) { timing->width = timing->width >> 1; timing->xres = timing->xres >> 1; timing->h_back_porch = timing->h_back_porch >> 1; timing->h_front_porch = timing->h_front_porch >> 1; timing->hsync_pulse_width = timing->hsync_pulse_width >> 1; + + if (phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC && + (phys_enc->comp_ratio > 1)) { + timing->extra_dto_cycles = + phys_enc->dsc_extra_pclk_cycle_cnt; + timing->width += phys_enc->dsc_extra_disp_width; + timing->h_back_porch += + phys_enc->dsc_extra_disp_width; + } + } + + /* + * for DSI, if compression is enabled, then divide the horizonal active + * timing parameters by compression ratio. + */ + if ((phys_enc->hw_intf->cap->type != INTF_DP) && + ((phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC))) { + // adjust active dimensions + timing->width = DIV_ROUND_UP(timing->width, phys_enc->comp_ratio); + timing->xres = DIV_ROUND_UP(timing->xres, phys_enc->comp_ratio); } } @@ -281,6 +308,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine( phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev; + if (phys_enc->hw_pp->dsc) + intf_cfg.dsc_num = phys_enc->hw_pp->dsc->idx; + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &timing_params, fmt); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index c002234..ee71cee 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DPU_HW_PINGPONG_H @@ -8,6 +9,7 @@ #include "dpu_hw_catalog.h" #include "dpu_hw_mdss.h" #include "dpu_hw_util.h" +#include "dpu_hw_dsc.h" #define DITHER_MATRIX_SZ 16 @@ -149,6 +151,7 @@ struct dpu_hw_pingpong { enum dpu_pingpong idx; const struct dpu_pingpong_cfg *caps; struct dpu_hw_merge_3d *merge_3d; + struct dpu_hw_dsc *dsc; /* ops */ struct dpu_hw_pingpong_ops ops; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 396429e..bb22ec8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s] " fmt, __func__ @@ -246,6 +247,11 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_dsc *hw; const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; + if (dsc->id < DSC_0 || dsc->id >= DSC_MAX) { + DPU_ERROR("skip dsc %d with invalid id\n", dsc->id); + continue; + } + hw = dpu_hw_dsc_init(dsc->id, mmio, cat); if (IS_ERR_OR_NULL(hw)) { rc = PTR_ERR(hw); @@ -535,8 +541,10 @@ static int _dpu_rm_make_reservation( } ret = _dpu_rm_reserve_dsc(rm, global_state, enc, &reqs->topology); - if (ret) + if (ret) { + DPU_ERROR("unable to find appropriate DSC\n"); return ret; + } return ret; } From patchwork Mon Jan 23 18:24:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuogee Hsieh X-Patchwork-Id: 13112746 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B51FC25B50 for ; Mon, 23 Jan 2023 18:26:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233777AbjAWS0R (ORCPT ); Mon, 23 Jan 2023 13:26:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37550 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233722AbjAWSZv (ORCPT ); Mon, 23 Jan 2023 13:25:51 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 069CA31E04; Mon, 23 Jan 2023 10:25:18 -0800 (PST) Received: from pps.filterd (m0279864.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30NDvPKX006849; Mon, 23 Jan 2023 18:25:11 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=KErrjc3xgE1bMROYd6zPKW0ZtuwKlGeYv2r3etNPY6E=; b=nelKSCwbRedweKBhLbXaglFkAmzrqFSrsNTg7nrQIjWMTuJ4QNWJIVo0qzEyB1FHQOmn H4vKDIBRqzeeFMZhhuV9YnFpoVfNoyfhPslAJCzGTX7Vr7TDEnYt9Vzx2hE1fZtAHWgB KIqoTjJu4VmYKho4bsDsUlMKkrkGYJTPvN5wxCTNrFykxHJNHZFEqVvX9BBc8NtqRE4q AQy6rkYufzZ/ZlH7XBloLgmi/vgpHyg/8/socDAxAKXcUcbEEr57t+5n1+roLA5Ysx+T zqRelZIPgIbuuNFa0SS1km1896+jDx9ksvFQvHsqTjvsY42BYuQPTlhsygrQzTlX6CUy Aw== Received: from nalasppmta02.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n89dr3hcj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:10 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA02.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30NIPAXY032366 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 23 Jan 2023 18:25:10 GMT Received: from khsieh-linux1.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Mon, 23 Jan 2023 10:25:09 -0800 From: Kuogee Hsieh To: , , , , , , , , , , CC: Kuogee Hsieh , , , , , Subject: [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block Date: Mon, 23 Jan 2023 10:24:34 -0800 Message-ID: <1674498274-6010-15-git-send-email-quic_khsieh@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> References: <1674498274-6010-1-git-send-email-quic_khsieh@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: RMcxm3L4YY1LFlihdTSGZoGR1L41zBsj X-Proofpoint-ORIG-GUID: RMcxm3L4YY1LFlihdTSGZoGR1L41zBsj X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-23_12,2023-01-23_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 clxscore=1015 priorityscore=1501 impostorscore=0 suspectscore=0 spamscore=0 adultscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 malwarescore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301230177 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch add DSC block and sub block to support new DSC v1.2 hardware encoder. Also sc7280 DSC related hardware information are added to allow sc7280 DSC feature be enabled at sc7280 platform. Signed-off-by: Kuogee Hsieh --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 50 +++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 7deffc9f9..2c78a46 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -476,6 +476,7 @@ static const struct dpu_caps sc7280_dpu_caps = { .has_idle_pc = true, .max_linewidth = 2400, .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + .max_dsc_width = 2560, }; static const struct dpu_mdp_cfg msm8998_mdp[] = { @@ -1707,7 +1708,7 @@ static const struct dpu_pingpong_cfg sm8350_pp[] = { }; static const struct dpu_pingpong_cfg sc7280_pp[] = { - PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_0", PINGPONG_0, 0x69000, 0, sc7280_pp_sblk, -1, -1), PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), @@ -1814,25 +1815,48 @@ static const struct dpu_merge_3d_cfg sm8550_merge_3d[] = { /************************************************************* * DSC sub blocks config *************************************************************/ -#define DSC_BLK(_name, _id, _base, _features) \ +#define DSC_BLK_HW_1_1(_name, _id, _base, _features) \ {\ .name = _name, .id = _id, \ .base = _base, .len = 0x140, \ - .features = _features, \ + .features = BIT(DPU_DSC_HW_REV_1_1) | _features, \ + } + +#define DSC_BLK_HW_1_2(_name, _id, _base, _features, _sblk) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0x140, \ + .features = BIT(DPU_DSC_HW_REV_1_2) | _features, \ + .sblk = &_sblk, \ } static struct dpu_dsc_cfg sdm845_dsc[] = { - DSC_BLK("dsc_0", DSC_0, 0x80000, 0), - DSC_BLK("dsc_1", DSC_1, 0x80400, 0), - DSC_BLK("dsc_2", DSC_2, 0x80800, 0), - DSC_BLK("dsc_3", DSC_3, 0x80c00, 0), + DSC_BLK_HW_1_1("dsc_0", DSC_0, 0x80000, 0), + DSC_BLK_HW_1_1("dsc_1", DSC_1, 0x80400, 0), + DSC_BLK_HW_1_1("dsc_2", DSC_2, 0x80800, 0), + DSC_BLK_HW_1_1("dsc_3", DSC_3, 0x80c00, 0), }; static struct dpu_dsc_cfg sm8150_dsc[] = { - DSC_BLK("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)), - DSC_BLK("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)), - DSC_BLK("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)), - DSC_BLK("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK_HW_1_1("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK_HW_1_1("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK_HW_1_1("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK_HW_1_1("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)), +}; + +static struct dpu_dsc_sub_blks sc7280_dsc_sblk_0 = { + .enc = {.base = 0x100, .len = 0x100}, + .ctl = {.base = 0xF00, .len = 0x10}, +}; + +static struct dpu_dsc_sub_blks sc7280_dsc_sblk_1 = { + .enc = {.base = 0x200, .len = 0x100}, + .ctl = {.base = 0xF80, .len = 0x10}, +}; + +static struct dpu_dsc_cfg sc7280_dsc[] = { + DSC_BLK_HW_1_2("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_NATIVE_422_EN), sc7280_dsc_sblk_0), + DSC_BLK_HW_1_2("dsc_1", DSC_1, 0x80000, BIT(DPU_DSC_NATIVE_422_EN), sc7280_dsc_sblk_1), }; /************************************************************* @@ -2809,6 +2833,8 @@ static const struct dpu_mdss_cfg sc7280_dpu_cfg = { .pingpong_count = ARRAY_SIZE(sc7280_pp), .pingpong = sc7280_pp, .intf_count = ARRAY_SIZE(sc7280_intf), + .dsc_count = ARRAY_SIZE(sc7280_dsc), + .dsc = sc7280_dsc, .intf = sc7280_intf, .vbif_count = ARRAY_SIZE(sdm845_vbif), .vbif = sdm845_vbif,