From 30e769eb272d3c4bd61864490aabbc54c2d4c4b3 Mon Sep 17 00:00:00 2001 From: Yao Xiao Date: Mon, 23 Jun 2025 20:17:57 +0800 Subject: [PATCH 01/10] net: mac80211: Added p2p0 for ap mode in softmac Change-Id: I364d7bc0a51907c9518f83e5a49697b00ee9cc11 Signed-off-by: Yao Xiao --- net/mac80211/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 683301d9f508..c78df0f7494b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1406,6 +1406,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) "Failed to add default virtual iface\n"); } + /* add one default AP interface if supported */ + if (local->hw.wiphy->interface_modes & (BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT)) && !ieee80211_hw_check(hw, NO_AUTO_VIF)) { + struct vif_params params = {0}; + + result = ieee80211_if_add(local, "p2p%d", NET_NAME_ENUM, NULL, + NL80211_IFTYPE_STATION, ¶ms); + if (result) + wiphy_warn(local->hw.wiphy, + "Failed to add p2p virtual iface\n"); + } + wiphy_unlock(hw->wiphy); rtnl_unlock(); From df347526e6d2ef58fb3fa533759dcda844e249ce Mon Sep 17 00:00:00 2001 From: ZhengRong Ruan Date: Thu, 28 Aug 2025 15:55:22 +0800 Subject: [PATCH 02/10] arm64: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nand.dts Signed-off-by: ZhengRong Ruan Change-Id: I6434268022e5e65234d25cfdc0daf31776786a00 --- arch/arm64/boot/dts/rockchip/Makefile | 1 + .../rv1126b-evb2-v12-fastboot-spi-nand.dts | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nand.dts diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index a2129674aedc..c96078654665 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -403,6 +403,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-rgb-Q7050ITH2641AA1T.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-emmc.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-spi-nand.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-iotest-v10.dtb diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nand.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nand.dts new file mode 100644 index 000000000000..d5ac2eec46fc --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nand.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +#include "rv1126b-evb2-v12.dts" +#include "rv1126b-fastboot-spi-nand.dtsi" + +/ { + model = "Rockchip RV1126B EVB2 V12 Arm64 Board"; + compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nand", "rockchip,rv1126b"; + + chosen { + bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; + }; +}; + +&ramdisk_r { + reg = <0x48c40000 (40 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x4b440000 (20 * 0x00100000)>; +}; From 2e2bf5a3c90441bfc37e8ab731c99ce185b81405 Mon Sep 17 00:00:00 2001 From: ZhengRong Ruan Date: Thu, 28 Aug 2025 15:56:54 +0800 Subject: [PATCH 03/10] ARM: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nand.dts Signed-off-by: ZhengRong Ruan Change-Id: I3784611206281c27536e9d1d27440a0c5573f235 --- arch/arm/boot/dts/Makefile | 1 + .../rv1126b-evb2-v12-fastboot-spi-nand.dts | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nand.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 43c79cf02f38..037c3288263a 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1202,6 +1202,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1126b-evb2-v12.dtb \ rv1126b-evb2-v12-aov-dual-cam.dtb \ rv1126b-evb2-v12-fastboot-emmc.dtb \ + rv1126b-evb2-v12-fastboot-spi-nand.dtb \ rv1126b-evb3-v10.dtb \ rv1126b-evb4-v10.dtb \ rv1126b-iotest-v10.dtb \ diff --git a/arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nand.dts b/arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nand.dts new file mode 100644 index 000000000000..62e5a66d88cb --- /dev/null +++ b/arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nand.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +#include "arm64/rockchip/rv1126b-evb2-v12-fastboot-spi-nand.dts" + +/ { + model = "Rockchip RV1126B EVB2 V12 Board"; + compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nand", "rockchip,rv1126b"; + + chosen { + bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; + }; +}; + +&ramdisk_r { + reg = <0x48c40000 (40 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x4b440000 (20 * 0x00100000)>; +}; From a79b096740911bc21994afa6cf643735a10d1bb3 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Thu, 28 Aug 2025 17:16:32 +0800 Subject: [PATCH 04/10] video: rockchip: rga3: remove useless mutex_unlock Fixes: c09c257b5d1a ("video: rockchip: rga3: fix map/unmap buffers in mutex_lock") Change-Id: Ic56df7f2c7ae6a44a5fe38afd04e33fc9e2c47cb Signed-off-by: Yu Qiaowei --- drivers/video/rockchip/rga3/rga_mm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index ba2ac0748d8d..e2dcc9b4f259 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -2385,8 +2385,6 @@ int rga_mm_import_buffer(struct rga_external_buffer *external_buffer, internal_buffer = kzalloc(sizeof(struct rga_internal_buffer), GFP_KERNEL); if (internal_buffer == NULL) { rga_err("%s alloc internal_buffer error!\n", __func__); - - mutex_unlock(&mm->lock); return -ENOMEM; } From 19441b6d78bda666827f9182832f93e2eb519d4f Mon Sep 17 00:00:00 2001 From: ZhengRong Ruan Date: Fri, 29 Aug 2025 10:41:11 +0800 Subject: [PATCH 05/10] arm64: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nor.dts Signed-off-by: ZhengRong Ruan Change-Id: I162eb480907811378ed8d92514dbea56a1617ee5 --- arch/arm64/boot/dts/rockchip/Makefile | 1 + .../rv1126b-evb2-v12-fastboot-spi-nor.dts | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nor.dts diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index c96078654665..5246e9d814f8 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -404,6 +404,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-emmc.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-spi-nand.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb2-v12-fastboot-spi-nor.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb3-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-evb4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rv1126b-iotest-v10.dtb diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nor.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nor.dts new file mode 100644 index 000000000000..11a0d82f54b2 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v12-fastboot-spi-nor.dts @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1126b-evb2-v12.dts" +#include "rv1126b-fastboot-spi-nor.dtsi" + +/ { + model = "Rockchip RV1126B EVB2 V12 Arm64 Board"; + compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nor", "rockchip,rv1126b"; + + chosen { + bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; + }; +}; + +&fspi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <750000000>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <1>; + }; +}; + +&ramdisk_r { + reg = <0x48c40000 (20 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x4a040000 (10 * 0x00100000)>; +}; From 78d43276e0944529cd42999df5b0cde9fab56884 Mon Sep 17 00:00:00 2001 From: ZhengRong Ruan Date: Fri, 29 Aug 2025 10:46:21 +0800 Subject: [PATCH 06/10] ARM: dts: rockchip: add rv1126b-evb2-v12-fastboot-spi-nor.dts Signed-off-by: ZhengRong Ruan Change-Id: If77f8ef62b32007a7ab6e04de0ad1138bbab645a --- arch/arm/boot/dts/Makefile | 1 + .../dts/rv1126b-evb2-v12-fastboot-spi-nor.dts | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nor.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 037c3288263a..8c2e97c96f99 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1203,6 +1203,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1126b-evb2-v12-aov-dual-cam.dtb \ rv1126b-evb2-v12-fastboot-emmc.dtb \ rv1126b-evb2-v12-fastboot-spi-nand.dtb \ + rv1126b-evb2-v12-fastboot-spi-nor.dtb \ rv1126b-evb3-v10.dtb \ rv1126b-evb4-v10.dtb \ rv1126b-iotest-v10.dtb \ diff --git a/arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nor.dts b/arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nor.dts new file mode 100644 index 000000000000..775cf1cfb910 --- /dev/null +++ b/arch/arm/boot/dts/rv1126b-evb2-v12-fastboot-spi-nor.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + */ + +#include "arm64/rockchip/rv1126b-evb2-v12-fastboot-spi-nor.dts" + +/ { + model = "Rockchip RV1126B EVB2 V12 Board"; + compatible = "rockchip,rv1126b-evb2-v12-fastboot-spi-nor", "rockchip,rv1126b"; + + chosen { + bootargs = "loglevel=0 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K"; + }; +}; + +&ramdisk_r { + reg = <0x48c40000 (20 * 0x00100000)>; +}; + +&ramdisk_c { + reg = <0x4a040000 (10 * 0x00100000)>; +}; From da450eccf5b0c72e5a7d351d9f5623d68986825a Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Fri, 28 Feb 2025 10:38:40 +0800 Subject: [PATCH 07/10] drm/rockchip: drv: Support parse vrr capbility in edid scds Change-Id: Iae91fe5ed41e2602bf94817d659f81586e2cb774 Signed-off-by: Algea Cao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 36 +++++++++++++++++++-- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 13 ++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 68342fd95cb5..e75d5bbaa88d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -885,7 +885,16 @@ void get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane) #define EDID_DSC_TOTAL_CHUNK_KBYTES 0x3f #define EDID_MAX_FRL_RATE_MASK 0xf0 -/* Sink Capability Data Structure, for compatibility with linux version < linux kernel 6.1 */ +#define DRM_EDID_FAPA_START (1 << 0) +#define DRM_EDID_ALLM (1 << 1) +#define DRM_EDID_FVA (1 << 2) +#define DRM_EDID_QMS (1 << 6) +#define DRM_EDID_VRR_MIN_MASK 0x3f +#define DRM_EDID_VRR_MAX_UPPER_MASK 0xc0 +#define DRM_EDID_QMS_TFR_MIN (1 << 4) +#define DRM_EDID_QMS_TFR_MAX (1 << 5) + +/* Sink Capability Data Structure */ static void parse_hdmi_forum_scds(struct rockchip_drm_hdmi21_data *hdmi21_data, const u8 *hf_scds) { if (hf_scds[7]) { @@ -893,9 +902,9 @@ static void parse_hdmi_forum_scds(struct rockchip_drm_hdmi21_data *hdmi21_data, u8 dsc_max_frl_rate; u8 dsc_max_slices; - DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; - hdmi21_data->allm_supported = hf_scds[8] & DRM_EDID_ALLM; + if (max_frl_rate) + DRM_DEBUG_KMS("hdmi21 FRL detected. parsing edid....\n"); get_max_frl_rate(max_frl_rate, &hdmi21_data->max_lanes, &hdmi21_data->max_frl_rate_per_lane); hdmi21_data->dsc_cap.v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; @@ -957,6 +966,27 @@ static void parse_hdmi_forum_scds(struct rockchip_drm_hdmi21_data *hdmi21_data, } } } + + /* parse additional bytes */ + if (cea_db_payload_len(hf_scds) >= 9) { + hdmi21_data->allm_supported = hf_scds[8] & DRM_EDID_ALLM; + hdmi21_data->vrr_cap.qms = hf_scds[8] & DRM_EDID_QMS; + hdmi21_data->vrr_cap.fva = hf_scds[8] & DRM_EDID_FVA; + hdmi21_data->vrr_cap.m_delta = hf_scds[8] & DRM_EDID_MDELTA; + hdmi21_data->vrr_cap.negm_vrr = hf_scds[8] & DRM_EDID_CNMVRR; + hdmi21_data->vrr_cap.cinema_vrr = hf_scds[8] & DRM_EDID_CINEMA_VRR; + } + + if (cea_db_payload_len(hf_scds) >= 11) { + hdmi21_data->vrr_cap.vrr_min = hf_scds[9] & DRM_EDID_VRR_MIN_MASK; + hdmi21_data->vrr_cap.vrr_max = + (hf_scds[9] & DRM_EDID_VRR_MAX_UPPER_MASK) << 2 | hf_scds[10]; + } + + if (cea_db_payload_len(hf_scds) >= 12) { + hdmi21_data->vrr_cap.qms_tfr_min = hf_scds[11] & DRM_EDID_QMS_TFR_MIN; + hdmi21_data->vrr_cap.qms_tfr_max = hf_scds[11] & DRM_EDID_QMS_TFR_MAX; + } } static diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 3fb7302a9ceb..30082987aac5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -626,11 +626,24 @@ struct rockchip_encoder { struct drm_encoder encoder; }; +struct rockchip_drm_vrr_cap { + bool qms; + bool m_delta; + bool cinema_vrr; + bool negm_vrr; + bool fva; + bool qms_tfr_max; + bool qms_tfr_min; + u8 vrr_min; + u16 vrr_max; +}; + struct rockchip_drm_hdmi21_data { u8 max_frl_rate_per_lane; u8 max_lanes; bool allm_supported; struct rockchip_drm_dsc_cap dsc_cap; + struct rockchip_drm_vrr_cap vrr_cap; }; void rockchip_connector_update_vfp_for_vrr(struct drm_crtc *crtc, struct drm_display_mode *mode, From d0e8f558bc58984f8f4508133143cc9ca77c8b0d Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Mon, 24 Feb 2025 17:09:02 +0800 Subject: [PATCH 08/10] drm/rockchip: vop2: Support hdmi qms-vrr Change-Id: Icc2931661b50a3a8168a98b983a676a74a9ba9da Signed-off-by: Algea Cao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 553 +++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 54 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 131 ++++- 3 files changed, 721 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index e75d5bbaa88d..8ca0dbd9d15d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -78,6 +78,502 @@ static const struct drm_driver rockchip_drm_driver; static unsigned int drm_debug; module_param_named(debug, drm_debug, int, 0600); +static const u16 tfr_vrefresh_table[TFR_MAX] = { + [TFR_QMSVRR_INACTIVE] = 0, + [TFR_23P97] = 2397, + [TFR_24] = 2400, + [TFR_25] = 2500, + [TFR_29P97] = 2997, + [TFR_30] = 3000, + [TFR_47P95] = 4795, + [TFR_48] = 4800, + [TFR_50] = 5000, + [TFR_59P94] = 5994, + [TFR_60] = 6000, + [TFR_100] = 10000, + [TFR_119P88] = 11988, + [TFR_120] = 12000, +}; + +/* BRR 720p60hz */ +static const struct mvrr_const_val const_hdmi720p60_6000 = { + .vrefresh_khz = 6000, + .vtotal_fixed = 750, +}; + +/** + * @vrefresh_khz: qms-vrr target refresh rate is 59.94Hz + * @vtotal_fixed: When switch to target refresh rate, vtotal is 750 + * @bit_len: frac_array's bit length + * @frac_array: Sources may also alternate between two sequential values + * of actual vtotal to better approximate the target refresh + * rate when target vtotal is fractional. For this example, + * the source vtotal would vary between 750 and 751. + * The value in frac_array indicates the order in which the + * vtotal changes during this process. Each bit of 0 indicates + * that the current frame vtotal is 750, and each bit of 1 + * indicates that the current frame vtotal is 751. + * Take 0x3f(00111111B) as an example, it represents a vtotal + * of 750 for the first and second frames, and 751 for the + * remaining six frames. 0xe3 and 0xfe also have the same meaning. + * The current frac_array represents the value of vtotal for 24 + * consecutive frames. + */ +static const struct mvrr_const_val const_hdmi720p60_5994 = { + .vrefresh_khz = 5994, + .vtotal_fixed = 750, /* 0.75 */ + .bit_len = 24, + .frac_array = {0x3f, 0xe3, 0xfe}, +}; + +static const struct mvrr_const_val const_hdmi720p60_5000 = { + .vrefresh_khz = 5000, + .vtotal_fixed = 900, +}; + +static const struct mvrr_const_val const_hdmi720p60_4800 = { + .vrefresh_khz = 4800, + .vtotal_fixed = 937, /* 0.5 */ + .bit_len = 8, + .frac_array = {0x3c}, +}; + +static const struct mvrr_const_val const_hdmi720p60_4795 = { + .vrefresh_khz = 4795, + .vtotal_fixed = 938, /* 0.4375 */ + .bit_len = 16, + .frac_array = {0x1e, 0x0e}, +}; + +static const struct mvrr_const_val const_hdmi720p60_3000 = { + .vrefresh_khz = 3000, + .vtotal_fixed = 1500, +}; + +static const struct mvrr_const_val const_hdmi720p60_2997 = { + .vrefresh_khz = 2997, + .vtotal_fixed = 1501, /* 0.5 */ + .bit_len = 56, + .frac_array = {0x1f, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xf8}, +}; + +static const struct mvrr_const_val const_hdmi720p60_2500 = { + .vrefresh_khz = 2500, + .vtotal_fixed = 1800, +}; + +static const struct mvrr_const_val const_hdmi720p60_2400 = { + .vrefresh_khz = 2400, + .vtotal_fixed = 1875, +}; + +static const struct mvrr_const_val const_hdmi720p60_2397 = { + .vrefresh_khz = 2397, + .vtotal_fixed = 1876, /* 0.875 */ + .bit_len = 40, + .frac_array = {0x1f, 0xff, 0xff, 0xff, 0xfc}, +}; + +/* BRR 720p120hz */ +static const struct mvrr_const_val const_hdmi720p120_12000 = { + .vrefresh_khz = 12000, + .vtotal_fixed = 750, +}; + +static const struct mvrr_const_val const_hdmi720p120_11988 = { + .vrefresh_khz = 11988, + .vtotal_fixed = 750, /* 0.75 */ + .bit_len = 24, + .frac_array = {0x3f, 0xe3, 0xfe}, +}; + +static const struct mvrr_const_val const_hdmi720p120_10000 = { + .vrefresh_khz = 10000, + .vtotal_fixed = 900, +}; + +static const struct mvrr_const_val const_hdmi720p120_6000 = { + .vrefresh_khz = 6000, + .vtotal_fixed = 1500, +}; + +static const struct mvrr_const_val const_hdmi720p120_5994 = { + .vrefresh_khz = 5994, + .vtotal_fixed = 1501, /* 0.5 */ + .bit_len = 56, + .frac_array = {0x0f, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xf8}, +}; + +static const struct mvrr_const_val const_hdmi720p120_5000 = { + .vrefresh_khz = 5000, + .vtotal_fixed = 1800, +}; + +static const struct mvrr_const_val const_hdmi720p120_4800 = { + .vrefresh_khz = 4800, + .vtotal_fixed = 1875, +}; + +static const struct mvrr_const_val const_hdmi720p120_4795 = { + .vrefresh_khz = 4795, + .vtotal_fixed = 1876, /* 0.875 */ + .bit_len = 40, + .frac_array = {0x1f, 0xff, 0xff, 0xff, 0xfc}, +}; + +static const struct mvrr_const_val const_hdmi720p120_3000 = { + .vrefresh_khz = 3000, + .vtotal_fixed = 3000, +}; + +static const struct mvrr_const_val const_hdmi720p120_2997 = { + .vrefresh_khz = 2997, + .vtotal_fixed = 3003, +}; + +static const struct mvrr_const_val const_hdmi720p120_2500 = { + .vrefresh_khz = 2500, + .vtotal_fixed = 3600, +}; + +static const struct mvrr_const_val const_hdmi720p120_2400 = { + .vrefresh_khz = 2400, + .vtotal_fixed = 3750, +}; + +static const struct mvrr_const_val const_hdmi720p120_2397 = { + .vrefresh_khz = 2397, + .vtotal_fixed = 3753, /* 0.75 */ + .bit_len = 88, + .frac_array = { + 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0 + }, +}; + +/* BRR 1080p60hz */ +static const struct mvrr_const_val const_hdmi1080p60_6000 = { + .vrefresh_khz = 6000, + .vtotal_fixed = 1125, +}; + +static const struct mvrr_const_val const_hdmi1080p60_5994 = { + .vrefresh_khz = 5994, + .vtotal_fixed = 1126, /* 0.125 */ + .bit_len = 24, + .frac_array = {0x00, 0x38, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi1080p60_5000 = { + .vrefresh_khz = 5000, + .vtotal_fixed = 1350, +}; + +static const struct mvrr_const_val const_hdmi1080p60_4800 = { + .vrefresh_khz = 4800, + .vtotal_fixed = 1406, /* 0.25 */ + .bit_len = 16, + .frac_array = {0x03, 0xc0}, +}; + +static const struct mvrr_const_val const_hdmi1080p60_4795 = { + .vrefresh_khz = 4795, + .vtotal_fixed = 1407, /* 0.65625 */ + .bit_len = 32, + .frac_array = {0x1f, 0xf1, 0x7f, 0xf0}, +}; + +static const struct mvrr_const_val const_hdmi1080p60_3000 = { + .vrefresh_khz = 3000, + .vtotal_fixed = 2250, +}; + +static const struct mvrr_const_val const_hdmi1080p60_2997 = { + .vrefresh_khz = 2997, + .vtotal_fixed = 2252, /* 0.25 */ + .bit_len = 56, + .frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi1080p60_2500 = { + .vrefresh_khz = 2500, + .vtotal_fixed = 2700, +}; + +static const struct mvrr_const_val const_hdmi1080p60_2400 = { + .vrefresh_khz = 2400, + .vtotal_fixed = 2812, /* 0.5 */ + .bit_len = 24, + .frac_array = {0x03, 0xff, 0xc0}, +}; + +static const struct mvrr_const_val const_hdmi1080p60_2397 = { + .vrefresh_khz = 2397, + .vtotal_fixed = 2815, /* 0.3125 */ + .bit_len = 128, + .frac_array = { + 0x00, 0x7f, 0x80, 0x00, 0x3f, 0xc0, 0x00, 0x0f, + 0xf0, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, + }, +}; + +/* BRR 1080p120hz */ +static const struct mvrr_const_val const_hdmi1080p120_12000 = { + .vrefresh_khz = 12000, + .vtotal_fixed = 1125, +}; + +static const struct mvrr_const_val const_hdmi1080p120_11988 = { + .vrefresh_khz = 11988, + .vtotal_fixed = 1126, /* 0.125 */ + .bit_len = 24, + .frac_array = {0x00, 0x38, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi1080p120_10000 = { + .vrefresh_khz = 10000, + .vtotal_fixed = 1350, +}; + +static const struct mvrr_const_val const_hdmi1080p120_6000 = { + .vrefresh_khz = 6000, + .vtotal_fixed = 2250, +}; + +static const struct mvrr_const_val const_hdmi1080p120_5994 = { + .vrefresh_khz = 5994, + .vtotal_fixed = 2252, /* 0.25 */ + .bit_len = 56, + .frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi1080p120_5000 = { + .vrefresh_khz = 5000, + .vtotal_fixed = 2700, +}; + +static const struct mvrr_const_val const_hdmi1080p120_4800 = { + .vrefresh_khz = 4800, + .vtotal_fixed = 2812, /* 0.5 */ + .bit_len = 24, + .frac_array = {0x03, 0xff, 0xc0}, +}; + +static const struct mvrr_const_val const_hdmi1080p120_4795 = { + .vrefresh_khz = 4795, + .vtotal_fixed = 2812, /* 0.3125 */ + .bit_len = 48, + .frac_array = {0x00, 0x3f, 0x80, 0x00, 0x3f, 0xc0}, +}; + +static const struct mvrr_const_val const_hdmi1080p120_3000 = { + .vrefresh_khz = 3000, + .vtotal_fixed = 4500, +}; + +static const struct mvrr_const_val const_hdmi1080p120_2997 = { + .vrefresh_khz = 2997, + .vtotal_fixed = 4504, /* 0.5 */ + .bit_len = 32, + .frac_array = {0x00, 0xff, 0xff, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi1080p120_2500 = { + .vrefresh_khz = 2500, + .vtotal_fixed = 5400, +}; + +static const struct mvrr_const_val const_hdmi1080p120_2400 = { + .vrefresh_khz = 2400, + .vtotal_fixed = 5625, +}; + +static const struct mvrr_const_val const_hdmi1080p120_2397 = { + .vrefresh_khz = 2397, + .vtotal_fixed = 5630, /* 0.625 */ + .bit_len = 48, + .frac_array = {0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00}, +}; + +/* BRR 2160p60hz */ +static const struct mvrr_const_val const_hdmi2160p60_6000 = { + .vrefresh_khz = 6000, + .vtotal_fixed = 2250, +}; + +static const struct mvrr_const_val const_hdmi2160p60_5994 = { + .vrefresh_khz = 5994, + .vtotal_fixed = 2252, /* 0.25 */ + .bit_len = 56, + .frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi2160p60_5000 = { + .vrefresh_khz = 5000, + .vtotal_fixed = 2700, +}; + +static const struct mvrr_const_val const_hdmi2160p60_4800 = { + .vrefresh_khz = 4800, + .vtotal_fixed = 2812, /* 0.5 */ + .bit_len = 24, + .frac_array = {0x03, 0xff, 0xc0}, +}; + +static const struct mvrr_const_val const_hdmi2160p60_4795 = { + .vrefresh_khz = 4795, + .vtotal_fixed = 2815, /* 0.3125 */ + .bit_len = 48, + .frac_array = {0x00, 0x3f, 0x80, 0x00, 0x3f, 0xc0}, +}; + +static const struct mvrr_const_val const_hdmi2160p60_3000 = { + .vrefresh_khz = 3000, + .vtotal_fixed = 4500, +}; + +static const struct mvrr_const_val const_hdmi2160p60_2997 = { + .vrefresh_khz = 2997, + .vtotal_fixed = 4504, /* 0.5 */ + .bit_len = 32, + .frac_array = {0x00, 0xff, 0xff, 0x00}, +}; + +static const struct mvrr_const_val const_hdmi2160p60_2500 = { + .vrefresh_khz = 2500, + .vtotal_fixed = 5400, +}; + +static const struct mvrr_const_val const_hdmi2160p60_2400 = { + .vrefresh_khz = 2400, + .vtotal_fixed = 5625, +}; + +static const struct mvrr_const_val const_hdmi2160p60_2397 = { + .vrefresh_khz = 2397, + .vtotal_fixed = 5630, /* 0.625 */ + .bit_len = 48, + .frac_array = {0x00, 0x3f, 0xff, 0xff, 0xff, 0x00}, +}; + +const struct mvrr_const_st const_hdmi1080p60_val = { + .brr_vic = HDMI_16_1920x1080P60_16x9, + .val = { + &const_hdmi1080p60_6000, + &const_hdmi1080p60_5994, + &const_hdmi1080p60_5000, + &const_hdmi1080p60_4800, + &const_hdmi1080p60_4795, + &const_hdmi1080p60_3000, + &const_hdmi1080p60_2997, + &const_hdmi1080p60_2500, + &const_hdmi1080p60_2400, + &const_hdmi1080p60_2397, + NULL, + }, +}; + +const struct mvrr_const_st const_hdmi1080p120_val = { + .brr_vic = HDMI_63_1920x1080P120_16x9, + .val = { + &const_hdmi1080p120_12000, + &const_hdmi1080p120_11988, + &const_hdmi1080p120_10000, + &const_hdmi1080p120_6000, + &const_hdmi1080p120_5994, + &const_hdmi1080p120_5000, + &const_hdmi1080p120_4800, + &const_hdmi1080p120_4795, + &const_hdmi1080p120_3000, + &const_hdmi1080p120_2997, + &const_hdmi1080p120_2500, + &const_hdmi1080p120_2400, + &const_hdmi1080p120_2397, + NULL, + }, +}; + +const struct mvrr_const_st const_hdmi720p60_val = { + .brr_vic = HDMI_4_1280x720P60_16x9, + .val = { + &const_hdmi720p60_6000, + &const_hdmi720p60_5994, + &const_hdmi720p60_5000, + &const_hdmi720p60_4800, + &const_hdmi720p60_4795, + &const_hdmi720p60_3000, + &const_hdmi720p60_2997, + &const_hdmi720p60_2500, + &const_hdmi720p60_2400, + &const_hdmi720p60_2397, + NULL, + }, +}; + +const struct mvrr_const_st const_hdmi720p120_val = { + .brr_vic = HDMI_47_1280x720P120_16x9, + .val = { + &const_hdmi720p120_12000, + &const_hdmi720p120_11988, + &const_hdmi720p120_10000, + &const_hdmi720p120_6000, + &const_hdmi720p120_5994, + &const_hdmi720p120_5000, + &const_hdmi720p120_4800, + &const_hdmi720p120_4795, + &const_hdmi720p120_3000, + &const_hdmi720p120_2997, + &const_hdmi720p120_2500, + &const_hdmi720p120_2400, + &const_hdmi720p120_2397, + NULL, + }, +}; + +const struct mvrr_const_st const_hdmi2160p60_val = { + .brr_vic = HDMI_97_3840x2160P60_16x9, + .val = { + &const_hdmi2160p60_6000, + &const_hdmi2160p60_5994, + &const_hdmi2160p60_5000, + &const_hdmi2160p60_4800, + &const_hdmi2160p60_4795, + &const_hdmi2160p60_3000, + &const_hdmi2160p60_2997, + &const_hdmi2160p60_2500, + &const_hdmi2160p60_2400, + &const_hdmi2160p60_2397, + NULL, + }, +}; + +/* The vtotal parameters of 4096x2160p60hz are the same as 3840x2160p60hz */ +const struct mvrr_const_st const_hdmismpte60_val = { + .brr_vic = HDMI_102_4096x2160P60_256x135, + .val = { + &const_hdmi2160p60_6000, + &const_hdmi2160p60_5994, + &const_hdmi2160p60_5000, + &const_hdmi2160p60_4800, + &const_hdmi2160p60_4795, + &const_hdmi2160p60_3000, + &const_hdmi2160p60_2997, + &const_hdmi2160p60_2500, + &const_hdmi2160p60_2400, + &const_hdmi2160p60_2397, + NULL, + }, +}; + +const struct mvrr_const_st *qms_const[] = { + &const_hdmi1080p60_val, + &const_hdmi1080p120_val, + &const_hdmi2160p60_val, + &const_hdmi720p60_val, + &const_hdmi720p120_val, + &const_hdmismpte60_val, + NULL, +}; + static inline bool rockchip_drm_debug_enabled(enum rockchip_drm_debug_category category) { return unlikely(drm_debug & category); @@ -1259,6 +1755,63 @@ void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc) priv->crtc_funcs[pipe] = NULL; } +u16 rockchip_hdmi_vrr_tfr_match_to_vrefresh(u8 tfr) +{ + if (tfr < 0 || tfr >= TFR_MAX) { + DRM_ERROR("qms-vrr tfr is out of range\n"); + return 0; + } + + return tfr_vrefresh_table[tfr]; +} + +const struct +mvrr_const_val *rockchip_hdmi_vrr_get_vrrconf_mconst(enum hdmi_brr_vic brr_vic, u16 vrefresh_khz) +{ + const struct mvrr_const_st **table_vic = NULL; + const struct mvrr_const_val *const *table_val = NULL; + + for (table_vic = qms_const; table_vic; table_vic++) { + if ((*table_vic)->brr_vic == brr_vic) { + table_val = (*table_vic)->val; + for (; table_val; table_val++) { + if ((*table_val)->vrefresh_khz == vrefresh_khz) + break; + } + break; + } + } + + if (!table_val) { + DRM_ERROR("%s[%d] not find brr_vic: %d vrefresh_khz: %d\n", + __func__, __LINE__, brr_vic, vrefresh_khz); + return NULL; + } + + return *table_val; +} + +u16 rockchip_hdmi_vrr_calc_new_vtotal(const struct mvrr_const_val *mvrr, u32 frame_cnt) +{ + u32 pos; + u16 vtotal = 0; + + if (!mvrr) + return vtotal; + + vtotal = mvrr->vtotal_fixed; + /* if bit_len is 0, then means there is no fraction */ + if (!mvrr->bit_len) + return vtotal; + + /* calculate the fraction number */ + pos = frame_cnt % mvrr->bit_len; + if (mvrr->frac_array[pos / 8] & (1 << (7 - (pos % 8)))) + vtotal++; + + return vtotal; +} + /* * a high frequency of page faults will follow up, if * there is a iommu fault, so it's better to limit the diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 30082987aac5..ddc85452c002 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -266,6 +266,14 @@ struct post_sharp { u32 regs[SHARP_REG_LENGTH / 4]; }; +struct rockchip_hdmi_vrr_state { + bool refresh_rate_ready_to_change; + bool m_const; + u8 next_tfr_val; + unsigned int vrr_frame_cnt; + const struct mvrr_const_val *mconst_val; +}; + struct rockchip_crtc_state { struct drm_crtc_state base; int vp_id; @@ -344,6 +352,7 @@ struct rockchip_crtc_state { struct drm_dsc_picture_parameter_set pps; struct rockchip_dsc_sink_cap dsc_sink_cap; struct rockchip_hdr_state hdr; + struct rockchip_hdmi_vrr_state hdmi_vrr; struct drm_property_blob *hdr_ext_data; struct drm_property_blob *acm_lut_data; struct drm_property_blob *post_csc_data; @@ -494,6 +503,47 @@ struct next_hdr_sink_data { struct ver_12_v2 ver_12_v2; } __packed; +/* refer to HDMI2.1B P453 */ +enum TARGET_FRAME_RATE { + TFR_QMSVRR_INACTIVE = 0, + TFR_23P97, + TFR_24, + TFR_25, + TFR_29P97, + TFR_30, + TFR_47P95, + TFR_48, + TFR_50, + TFR_59P94, + TFR_60, + TFR_100, + TFR_119P88, + TFR_120, + TFR_MAX, +}; + +enum hdmi_brr_vic { + HDMI_16_1920x1080P60_16x9 = 16, + HDMI_63_1920x1080P120_16x9 = 63, + HDMI_4_1280x720P60_16x9 = 4, + HDMI_47_1280x720P120_16x9 = 47, + HDMI_97_3840x2160P60_16x9 = 97, + HDMI_102_4096x2160P60_256x135 = 102, +}; + +struct mvrr_const_val { + /* unit: 100 6000, 5994, 5000, 3000, 2997, 2500, 2400, 2397 */ + u16 vrefresh_khz; + u16 vtotal_fixed; /* vtotal_fixed is mutex with bit_len */ + u8 bit_len; /* current max value is 16 * 8, 128 */ + u8 frac_array[16]; +}; + +struct mvrr_const_st { + enum hdmi_brr_vic brr_vic; /* the vic of brr */ + const struct mvrr_const_val *val[]; +}; + /* * Rockchip drm private crtc funcs. * @loader_protect: protect loader logo crtc's power @@ -721,6 +771,10 @@ __printf(3, 4) void rockchip_drm_dbg_thread_info(const struct device *dev, enum rockchip_drm_debug_category category, const char *format, ...); +u16 rockchip_hdmi_vrr_tfr_match_to_vrefresh(u8 tfr); +const struct +mvrr_const_val *rockchip_hdmi_vrr_get_vrrconf_mconst(enum hdmi_brr_vic brr_vic, u16 vrefresh_khz); +u16 rockchip_hdmi_vrr_calc_new_vtotal(const struct mvrr_const_val *mvrr, u32 frame_cnt); extern struct platform_driver cdn_dp_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 11c9fbac60f7..e6a26e75deb8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -5955,6 +5955,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, vcstate->splice_mode = false; vcstate->output_flags = 0; vcstate->output_type = 0; + vcstate->hdmi_vrr.m_const = 0; + vcstate->hdmi_vrr.next_tfr_val = 0; + vcstate->hdmi_vrr.refresh_rate_ready_to_change = false; vp->splice_mode_right = false; vp->loader_protect = false; vp->enabled_win_mask = 0; @@ -10682,10 +10685,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta VOP_MODULE_SET(vop2, vp, dsp_vtotal, vtotal); VOP_MODULE_SET(vop2, vp, dsp_vs_end, vsync_len); - /** - * when display interface support vrr, config vtotal valid immediately + /* + * when display interface support vrr, config vtotal + * valid immediately except HDMI QMS-VRR. HDMI QMS-VRR + * requires cfg done to accurately handle the vrr process. + * Fixme: HDMI GAMING-VRR needs to config vtotal valid immediately, + * the next version will be implemented. */ - if (vcstate->max_refresh_rate && vcstate->min_refresh_rate) + if (vcstate->max_refresh_rate && vcstate->min_refresh_rate && + !output_if_is_hdmi(vcstate->output_if)) VOP_MODULE_SET(vop2, vp, sw_dsp_vtotal_imd, 1); snprintf(clk_name, sizeof(clk_name), "dclk_out%d", vp->id); @@ -12502,22 +12510,13 @@ static void vop2_crtc_hfp_seamless_switch(struct drm_crtc *crtc) VOP_MODULE_SET(vop2, vp, htotal_pw, (new_htotal << 16) | hsync_len); } -static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc) +static void +vop2_crtc_update_vrr_timing(struct drm_crtc *crtc, unsigned int new_vtotal, unsigned int new_vfp) { struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; struct drm_display_mode *adjust_mode = &crtc->state->adjusted_mode; - unsigned int vrefresh; - unsigned int new_vtotal, vfp, new_vfp; - - DRM_DEV_INFO(vop2->dev, "change refresh rate by changing vfp\n"); - vrefresh = drm_mode_vrefresh(adjust_mode); - - /* calculate new vfp for new refresh rate */ - new_vtotal = adjust_mode->vtotal * vrefresh / vcstate->request_refresh_rate; - vfp = adjust_mode->vsync_start - adjust_mode->vdisplay; - new_vfp = vfp + new_vtotal - adjust_mode->vtotal; /* config vop2 vtotal register */ VOP_MODULE_SET(vop2, vp, dsp_vtotal, new_vtotal); @@ -12539,13 +12538,81 @@ static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc) rockchip_connector_update_vfp_for_vrr(crtc, adjust_mode, new_vfp); } +static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc) +{ + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + struct drm_display_mode *adjust_mode = &crtc->state->adjusted_mode; + struct rockchip_hdmi_vrr_state *hdmi_vrr = &vcstate->hdmi_vrr; + unsigned int vrefresh, vrefresh_khz; + unsigned int new_vtotal, vfp, new_vfp; + u8 brr_vic; + + DRM_DEV_DEBUG(vop2->dev, "change refresh rate by changing vfp\n"); + /* + * If next_tfr_val is no zero, current mode is hdmi qms-vrr. + * If next_tfr_val is 0, it indicates that current mode is hdmi + * gaming-vrr/fva, or eDP/DSI vrr. + */ + if (hdmi_vrr->next_tfr_val) { + brr_vic = drm_match_cea_mode(adjust_mode); + if (!brr_vic) { + DRM_ERROR("qms vrr can't support resolution:\n"); + DRM_ERROR(DRM_MODE_FMT "\n", DRM_MODE_ARG(adjust_mode)); + return; + } + + vrefresh_khz = rockchip_hdmi_vrr_tfr_match_to_vrefresh(hdmi_vrr->next_tfr_val); + if (!vrefresh_khz) { + DRM_ERROR("qms vrr unsupported tfr:%d\n", hdmi_vrr->next_tfr_val); + return; + } + + hdmi_vrr->mconst_val = rockchip_hdmi_vrr_get_vrrconf_mconst(brr_vic, vrefresh_khz); + if (!hdmi_vrr->mconst_val) { + DRM_ERROR("qms vrr can't find mconst_val\n"); + return; + } + + hdmi_vrr->vrr_frame_cnt = 0; + new_vtotal = rockchip_hdmi_vrr_calc_new_vtotal(hdmi_vrr->mconst_val, + hdmi_vrr->vrr_frame_cnt); + if (!new_vtotal) { + DRM_ERROR("qms vrr invalid vtotal\n"); + return; + } + hdmi_vrr->vrr_frame_cnt++; + vfp = adjust_mode->vsync_start - adjust_mode->vdisplay; + new_vfp = vfp + new_vtotal - adjust_mode->vtotal; + hdmi_vrr->refresh_rate_ready_to_change = false; + } else { + vrefresh = drm_mode_vrefresh(adjust_mode); + + /* calculate new vfp for new refresh rate */ + new_vtotal = adjust_mode->vtotal * vrefresh / vcstate->request_refresh_rate; + vfp = adjust_mode->vsync_start - adjust_mode->vdisplay; + new_vfp = vfp + new_vtotal - adjust_mode->vtotal; + } + vop2_crtc_update_vrr_timing(crtc, new_vtotal, new_vfp); +} + static void vop2_crtc_update_vrr(struct drm_crtc *crtc) { struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); struct vop2_video_port *vp = to_vop2_video_port(crtc); - if (!vp->refresh_rate_change) - return; + /* + * In hdmi qms vrr scenarios, it is possible to switch + * timing several frames after refresh rate is configured + */ + if (output_if_is_hdmi(vcstate->output_if)) { + if (!vcstate->hdmi_vrr.refresh_rate_ready_to_change) + return; + } else { + if (!vp->refresh_rate_change) + return; + } if (!vcstate->min_refresh_rate || !vcstate->max_refresh_rate) return; @@ -12722,7 +12789,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat vop2_wait_for_scan_timing_max_to_assigned_line(vp, current_line, assigned_line); } - if (vop2->version == VOP_VERSION_RK3588) + if (vop2->version == VOP_VERSION_RK3588 || vop2->version == VOP_VERSION_RK3576) vop2_crtc_update_vrr(crtc); /* Process cluster sub windows overlay. */ @@ -14249,6 +14316,34 @@ static void vop2_dsc_isr(struct vop2 *vop2) } } +static void vop2_frac_mvrr_update(struct drm_crtc *crtc, struct vop2_video_port *vp) +{ + struct rockchip_crtc_state *vcstate; + struct drm_display_mode *adjust_mode; + unsigned int new_vtotal, vfp, new_vfp; + + vcstate = to_rockchip_crtc_state(crtc->state); + /* + * When hdmi qms-vrr is enabled and M_VRR(The difference between + * current refresh rate vfp and the vfp of the base fresh rate) + * is fractional. Sources should alternate between two sequential + * values of M_VRR to better approximate the fractional M_VRR. + */ + if (vcstate->hdmi_vrr.next_tfr_val && vcstate->hdmi_vrr.m_const) { + adjust_mode = &crtc->state->adjusted_mode; + new_vtotal = rockchip_hdmi_vrr_calc_new_vtotal(vcstate->hdmi_vrr.mconst_val, + vcstate->hdmi_vrr.vrr_frame_cnt); + if (!new_vtotal) { + DRM_ERROR("qms vrr invalid vtotal\n"); + } else { + vfp = adjust_mode->vsync_start - adjust_mode->vdisplay; + new_vfp = vfp + new_vtotal - adjust_mode->vtotal; + vop2_crtc_update_vrr_timing(crtc, new_vtotal, new_vfp); + vcstate->hdmi_vrr.vrr_frame_cnt++; + } + } +} + static irqreturn_t vop2_isr(int irq, void *data) { struct vop2 *vop2 = data; @@ -14340,6 +14435,7 @@ static irqreturn_t vop2_isr(int irq, void *data) drm_crtc_handle_vblank(crtc); vop2_handle_vblank(vop2, crtc); } + vop2_frac_mvrr_update(crtc, vp); active_irqs &= ~FS_FIELD_INTR; ret = IRQ_HANDLED; } @@ -14544,6 +14640,7 @@ static irqreturn_t vop3_vp_isr(int irq, void *data) rockchip_drm_dbg(vop2->dev, VOP_DEBUG_VSYNC, "vsync_vp%d", vp->id); drm_crtc_handle_vblank(crtc); vop2_handle_vblank(vop2, crtc); + vop2_frac_mvrr_update(crtc, vp); active_irqs &= ~FS_FIELD_INTR; ret = IRQ_HANDLED; } From 5a89a1cb8b9c3cba5666151e838d2a3d760fe0ea Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Mon, 24 Feb 2025 17:12:52 +0800 Subject: [PATCH 09/10] drm/bridge: synopsys: dw-hdmi-qp: Support qms-vrr Change-Id: Idad7f638df53c78bbaf4485623a326d723e2892b Signed-off-by: Algea Cao --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 83 +++++ drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h | 1 + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 329 ++++++++++++++++++- include/drm/bridge/dw_hdmi.h | 3 + 4 files changed, 406 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 118153b0572d..2feb2f27a721 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -327,6 +327,8 @@ struct dw_hdmi_qp { bool hdr2sdr; bool flt_no_timeout; + u8 next_tfr; + bool m_const; u32 scdc_intr; u32 flt_intr; u32 earc_intr; @@ -1768,6 +1770,67 @@ static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi) PKTSCHED_PKT_EN); } +static void dw_hdmi_qp_config_vtem_class1(struct dw_hdmi_qp *hdmi, bool m_const, u8 next_tfr) +{ + struct drm_display_mode *mode = &hdmi->previous_mode; + u8 ds_type = 0; + u8 sync = 1; + u8 vfr = 1; + u8 afr = 0; + u8 new = 1; + u8 end = 1; + u8 data_set_length = 4; + u8 base_vfp; + u16 base_refresh_l, base_refresh_h; + u32 val, i; + + if (!next_tfr) { + hdmi_modb(hdmi, 0, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN); + return; + } + + val = 0xc0 << 8; + hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS0); + + val = new << 7 | end << 6 | ds_type << 4 | afr << 3 | + vfr << 2 | sync << 1; + hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS1); + + if (m_const) + val = 0x6 << 24; + else + val = 0x4 << 24; + + val |= data_set_length << 16; + hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS2); + + base_vfp = mode->vsync_start - mode->vdisplay; + base_refresh_l = drm_mode_vrefresh(mode); + base_refresh_h = (base_refresh_l >> 8) & 0x3; + base_refresh_l &= 0xff; + + val = base_refresh_l << 16 | next_tfr << 11 | base_refresh_h << 8 | base_vfp; + hdmi_writel(hdmi, val, PKT_EMP_VTEM_CONTENTS3); + + for (i = PKT_EMP_VTEM_CONTENTS4; i <= PKT_EMP_VTEM_CONTENTS7; i += 4) + hdmi_writel(hdmi, 0, i); + + hdmi_modb(hdmi, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN); +} + +static void dw_hdmi_qp_config_vtem(struct dw_hdmi_qp *hdmi) +{ + if (hdmi->disabled || !hdmi->dclk_en) + return; + + if (!hdmi->next_tfr) { + hdmi_modb(hdmi, 0, PKTSCHED_EMP_VTEM_TX_EN, PKTSCHED_PKT_EN); + return; + } + + dw_hdmi_qp_config_vtem_class1(hdmi, hdmi->m_const, hdmi->next_tfr); +} + static void hdmi_config_drm_infoframe(struct dw_hdmi_qp *hdmi, const struct drm_connector *connector) { @@ -2588,6 +2651,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, hdmi_config_AVI(hdmi, connector, mode); hdmi_config_vendor_specific_infoframe(hdmi, connector, mode); hdmi_config_CVTEM(hdmi); + dw_hdmi_qp_config_vtem_class1(hdmi, hdmi->m_const, hdmi->next_tfr); hdmi_config_drm_infoframe(hdmi, connector); ret = hdmi_set_op_mode(hdmi, link_cfg, connector); if (ret) { @@ -2963,6 +3027,24 @@ out: } EXPORT_SYMBOL_GPL(dw_hdmi_qp_handle_hpd); +void dw_hdmi_qp_set_qms(struct dw_hdmi_qp *hdmi, u8 next_tfr, u8 m_const) +{ + if (!hdmi) + return; + + hdmi->next_tfr = next_tfr; + hdmi->m_const = m_const; + + dw_hdmi_qp_config_vtem(hdmi); +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_qms); + +u8 dw_hdmi_qp_get_next_tfr(struct dw_hdmi_qp *hdmi) +{ + return hdmi->next_tfr; +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_get_next_tfr); + static int dw_hdmi_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, @@ -3468,6 +3550,7 @@ static void dw_hdmi_connector_atomic_commit(struct drm_connector *connector, if (hdmi->hdmi_changed_status & HDMI_VSIF_CHANGED) hdmi_config_vendor_specific_infoframe(hdmi, hdmi->curr_conn, &hdmi->previous_mode); + dw_hdmi_qp_config_vtem_class1(hdmi, hdmi->m_const, hdmi->next_tfr); } } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h index 8392b1350d3a..022cb47babbf 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h @@ -222,6 +222,7 @@ #define PKTSCHED_AVI_TX_EN BIT(13) #define PKTSCHED_VSI_TX_EN BIT(12) #define PKTSCHED_EMP_CVTEM_TX_EN BIT(10) +#define PKTSCHED_EMP_VTEM_TX_EN BIT(9) #define PKTSCHED_AMD_TX_EN BIT(8) #define PKTSCHED_GCP_TX_EN BIT(3) #define PKTSCHED_AUDS_TX_EN BIT(2) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 9eebcfaa85cb..4f60e065019a 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -25,6 +25,7 @@ #include #include #include +#include #include