3 Commits

Author SHA1 Message Date
nikkuss c8afdbf71a add qcom_battmgr, 7.1 uses it instead of surface EC for battery info 2026-06-17 01:04:03 +04:00
nikkuss 30c7f18e47 bump kernel to 7.1.0 2026-06-16 07:42:29 +04:00
nikkuss 931cf9966b add VRR 2026-05-29 22:13:40 +04:00
6 changed files with 606 additions and 269 deletions
-1
View File
@@ -66,7 +66,6 @@
]; ];
blacklistedKernelModules = [ blacklistedKernelModules = [
"qcom_battmgr"
"qcrypto" "qcrypto"
]; ];
+20 -16
View File
@@ -1,23 +1,27 @@
{ {
description = "Surface Laptop 7 (x1e80100 / Snapdragon X Elite) kernel and hardware support"; description = "Surface Laptop 7 (x1e80100 / Snapdragon X Elite) kernel and hardware support";
outputs = { self }: { outputs =
nixosModules = { { self }:
default = self.nixosModules.all; {
nixosModules = {
default = self.nixosModules.all;
all = { ... }: { all =
imports = [ { ... }:
self.nixosModules.kernel {
self.nixosModules.kernel-modules imports = [
self.nixosModules.boot self.nixosModules.kernel
self.nixosModules.hardware self.nixosModules.kernel-modules
]; self.nixosModules.boot
self.nixosModules.hardware
];
};
kernel = import ./kernel.nix;
kernel-modules = import ./kernel-modules.nix;
boot = import ./boot.nix;
hardware = import ./hardware.nix;
}; };
kernel = import ./kernel.nix;
kernel-modules = import ./kernel-modules.nix;
boot = import ./boot.nix;
hardware = import ./hardware.nix;
}; };
};
} }
+16 -6
View File
@@ -1,13 +1,23 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
dtbName = { dtbName =
"13" = "qcom/x1e80100-microsoft-romulus13.dtb"; {
"15" = "qcom/x1e80100-microsoft-romulus15.dtb"; "13" = "qcom/x1e80100-microsoft-romulus13.dtb";
}.${config.x1e.model}; "15" = "qcom/x1e80100-microsoft-romulus15.dtb";
}
.${config.x1e.model};
in in
{ {
options.x1e.model = lib.mkOption { options.x1e.model = lib.mkOption {
type = lib.types.enum [ "13" "15" ]; type = lib.types.enum [
"13"
"15"
];
default = "13"; default = "13";
description = "Surface Laptop 7 display size (13.8\" or 15\")."; description = "Surface Laptop 7 display size (13.8\" or 15\").";
}; };
+278 -242
View File
@@ -1,252 +1,288 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
kernel = config.boot.kernelPackages.kernel; kernel = config.boot.kernelPackages.kernel;
spi-hid = pkgs.stdenv.mkDerivation { spi-hid = pkgs.stdenv.mkDerivation {
pname = "spi-hid"; pname = "spi-hid";
version = "0.3.1-${kernel.version}"; version = "0.3.1-${kernel.version}";
src = ./kernel/modules/spi-hid; src = ./kernel/modules/spi-hid;
hardeningDisable = [ hardeningDisable = [
"pic" "pic"
"format" "format"
]; ];
nativeBuildInputs = kernel.moduleBuildDependencies ++ [ pkgs.kmod ]; nativeBuildInputs = kernel.moduleBuildDependencies ++ [ pkgs.kmod ];
makeFlags = [ makeFlags = [
"KERNELRELEASE=${kernel.modDirVersion}" "KERNELRELEASE=${kernel.modDirVersion}"
"KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" "KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
"INSTALL_MOD_PATH=$(out)" "INSTALL_MOD_PATH=$(out)"
]; ];
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \ make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \
M=$(pwd) \ M=$(pwd) \
ARCH=${pkgs.stdenv.hostPlatform.linuxArch} \ ARCH=${pkgs.stdenv.hostPlatform.linuxArch} \
modules modules
runHook postBuild runHook postBuild
''; '';
installPhase = '' installPhase = ''
runHook preInstall runHook preInstall
install -D -m 644 spi-hid.ko $out/lib/modules/${kernel.modDirVersion}/extra/spi-hid.ko install -D -m 644 spi-hid.ko $out/lib/modules/${kernel.modDirVersion}/extra/spi-hid.ko
runHook postInstall runHook postInstall
''; '';
enableParallelBuilding = true; enableParallelBuilding = true;
meta = with lib; { meta = with lib; {
description = "HID over SPI (HIDSPI v3) QSPI transport driver"; description = "HID over SPI (HIDSPI v3) QSPI transport driver";
license = licenses.gpl2Only; license = licenses.gpl2Only;
platforms = platforms.linux; platforms = platforms.linux;
}; };
}; };
ath12k-norfkill = pkgs.stdenv.mkDerivation {
pname = "ath12k-norfkill";
inherit (kernel)
src
version
postPatch
nativeBuildInputs
;
kernel_dev = kernel.dev;
kernelVersion = kernel.modDirVersion;
patches = [
./kernel/modules/ath12k/disable-rfkill.patch
];
buildPhase = ''
BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build
cp $BUILT_KERNEL/Module.symvers .
cp $BUILT_KERNEL/.config .
cp $kernel_dev/vmlinux .
make "-j$NIX_BUILD_CORES" modules_prepare
make "-j$NIX_BUILD_CORES" M=drivers/net/wireless/ath/ath12k modules
'';
installPhase = ''
install -D -m 644 drivers/net/wireless/ath/ath12k/ath12k.ko \
$out/lib/modules/${kernel.modDirVersion}/extra/ath12k.ko
if [ -f drivers/net/wireless/ath/ath12k/wifi7/ath12k_wifi7.ko ]; then
install -D -m 644 drivers/net/wireless/ath/ath12k/wifi7/ath12k_wifi7.ko \
$out/lib/modules/${kernel.modDirVersion}/extra/ath12k_wifi7.ko
fi
'';
meta = with lib; {
description = "ath12k with rfkill config early-return workaround";
license = licenses.bsd3;
platforms = platforms.linux;
};
};
ath12k-norfkill = pkgs.stdenv.mkDerivation { gpi-qspi = pkgs.stdenv.mkDerivation {
pname = "ath12k-norfkill"; pname = "gpi-qspi";
inherit (kernel) inherit (kernel)
src src
version version
postPatch postPatch
nativeBuildInputs nativeBuildInputs
; ;
kernel_dev = kernel.dev; kernel_dev = kernel.dev;
kernelVersion = kernel.modDirVersion; kernelVersion = kernel.modDirVersion;
patches = [ patches = [
./kernel/modules/ath12k/disable-rfkill.patch ./kernel/modules/qcom-qspi/gpi.patch
]; ];
buildPhase = '' buildPhase = ''
BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build
cp $BUILT_KERNEL/Module.symvers . cp $BUILT_KERNEL/Module.symvers .
cp $BUILT_KERNEL/.config . cp $BUILT_KERNEL/.config .
cp $kernel_dev/vmlinux . cp $kernel_dev/vmlinux .
make "-j$NIX_BUILD_CORES" modules_prepare make "-j$NIX_BUILD_CORES" modules_prepare
make "-j$NIX_BUILD_CORES" M=drivers/net/wireless/ath/ath12k modules make "-j$NIX_BUILD_CORES" M=drivers/dma/qcom modules
''; '';
installPhase = '' installPhase = ''
install -D -m 644 drivers/net/wireless/ath/ath12k/ath12k.ko \ make \
$out/lib/modules/${kernel.modDirVersion}/extra/ath12k.ko INSTALL_MOD_PATH="$out" \
if [ -f drivers/net/wireless/ath/ath12k/wifi7/ath12k_wifi7.ko ]; then XZ="xz -T$NIX_BUILD_CORES" \
install -D -m 644 drivers/net/wireless/ath/ath12k/wifi7/ath12k_wifi7.ko \ M="drivers/dma/qcom" \
$out/lib/modules/${kernel.modDirVersion}/extra/ath12k_wifi7.ko modules_install
fi '';
''; meta = with lib; {
meta = with lib; { description = "Qualcomm GPI DMA with QSPI protocol 9 support";
description = "ath12k with rfkill config early-return workaround"; license = licenses.gpl2Only;
license = licenses.bsd3; platforms = platforms.linux;
platforms = platforms.linux; };
}; };
};
gpi-qspi = pkgs.stdenv.mkDerivation { spi-geni-qcom-qspi = pkgs.stdenv.mkDerivation {
pname = "gpi-qspi"; pname = "spi-geni-qcom-qspi";
inherit (kernel) inherit (kernel)
src src
version version
postPatch postPatch
nativeBuildInputs nativeBuildInputs
; ;
kernel_dev = kernel.dev; kernel_dev = kernel.dev;
kernelVersion = kernel.modDirVersion; kernelVersion = kernel.modDirVersion;
patches = [ patches = [
./kernel/modules/qcom-qspi/gpi.patch ./kernel/modules/qcom-qspi/gpi.patch
]; ./kernel/modules/qcom-qspi/spi-geni-qcom.patch
buildPhase = '' ];
BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build buildPhase = ''
cp $BUILT_KERNEL/Module.symvers . BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build
cp $BUILT_KERNEL/.config . cp $BUILT_KERNEL/Module.symvers .
cp $kernel_dev/vmlinux . cp $BUILT_KERNEL/.config .
make "-j$NIX_BUILD_CORES" modules_prepare cp $kernel_dev/vmlinux .
make "-j$NIX_BUILD_CORES" M=drivers/dma/qcom modules make "-j$NIX_BUILD_CORES" modules_prepare
''; make "-j$NIX_BUILD_CORES" M=drivers/spi CONFIG_SPI_QCOM_GENI=m
installPhase = '' '';
make \ installPhase = ''
INSTALL_MOD_PATH="$out" \ install -D -m 644 drivers/spi/spi-geni-qcom.ko \
XZ="xz -T$NIX_BUILD_CORES" \ $out/lib/modules/${kernel.modDirVersion}/extra/spi-geni-qcom.ko
M="drivers/dma/qcom" \ '';
modules_install meta = with lib; {
''; description = "Qualcomm GENI SPI with QSPI 1-4-4 support";
meta = with lib; { license = licenses.gpl2Only;
description = "Qualcomm GPI DMA with QSPI protocol 9 support"; platforms = platforms.linux;
license = licenses.gpl2Only; };
platforms = platforms.linux; };
};
};
spi-geni-qcom-qspi = pkgs.stdenv.mkDerivation { cpu-parking = pkgs.stdenv.mkDerivation {
pname = "spi-geni-qcom-qspi"; pname = "cpu-parking";
inherit (kernel) version = "0.1.0-${kernel.version}";
src src = ./kernel/modules/cpu-parking;
version hardeningDisable = [
postPatch "pic"
nativeBuildInputs "format"
; ];
kernel_dev = kernel.dev; nativeBuildInputs = kernel.moduleBuildDependencies ++ [ pkgs.kmod ];
kernelVersion = kernel.modDirVersion; makeFlags = [
patches = [ "KERNELRELEASE=${kernel.modDirVersion}"
./kernel/modules/qcom-qspi/gpi.patch "KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
./kernel/modules/qcom-qspi/spi-geni-qcom.patch "INSTALL_MOD_PATH=$(out)"
]; ];
buildPhase = '' buildPhase = ''
BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build runHook preBuild
cp $BUILT_KERNEL/Module.symvers . make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \
cp $BUILT_KERNEL/.config . M=$(pwd) \
cp $kernel_dev/vmlinux . ARCH=${pkgs.stdenv.hostPlatform.linuxArch} \
make "-j$NIX_BUILD_CORES" modules_prepare modules
make "-j$NIX_BUILD_CORES" M=drivers/spi CONFIG_SPI_QCOM_GENI=m runHook postBuild
''; '';
installPhase = '' installPhase = ''
install -D -m 644 drivers/spi/spi-geni-qcom.ko \ runHook preInstall
$out/lib/modules/${kernel.modDirVersion}/extra/spi-geni-qcom.ko install -D -m 644 cpu_parking.ko $out/lib/modules/${kernel.modDirVersion}/extra/cpu_parking.ko
''; runHook postInstall
meta = with lib; { '';
description = "Qualcomm GENI SPI with QSPI 1-4-4 support"; enableParallelBuilding = true;
license = licenses.gpl2Only; meta = with lib; {
platforms = platforms.linux; description = "CPU core parking for Snapdragon X Elite (x1e80100)";
}; license = licenses.gpl2Only;
}; platforms = platforms.linux;
};
};
cpu-parking = pkgs.stdenv.mkDerivation { ec-reboot = pkgs.stdenv.mkDerivation {
pname = "cpu-parking"; pname = "ec-reboot";
version = "0.1.0-${kernel.version}"; version = "0.1.0-${kernel.version}";
src = ./kernel/modules/cpu-parking; src = ./kernel/modules/ec-reboot;
hardeningDisable = [ hardeningDisable = [
"pic" "pic"
"format" "format"
]; ];
nativeBuildInputs = kernel.moduleBuildDependencies ++ [ pkgs.kmod ]; nativeBuildInputs = kernel.moduleBuildDependencies ++ [ pkgs.kmod ];
makeFlags = [ makeFlags = [
"KERNELRELEASE=${kernel.modDirVersion}" "KERNELRELEASE=${kernel.modDirVersion}"
"KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" "KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
"INSTALL_MOD_PATH=$(out)" "INSTALL_MOD_PATH=$(out)"
]; ];
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \ make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \
M=$(pwd) \ M=$(pwd) \
ARCH=${pkgs.stdenv.hostPlatform.linuxArch} \ ARCH=${pkgs.stdenv.hostPlatform.linuxArch} \
modules modules
runHook postBuild runHook postBuild
''; '';
installPhase = '' installPhase = ''
runHook preInstall runHook preInstall
install -D -m 644 cpu_parking.ko $out/lib/modules/${kernel.modDirVersion}/extra/cpu_parking.ko install -D -m 644 ec-reboot.ko $out/lib/modules/${kernel.modDirVersion}/extra/ec-reboot.ko
runHook postInstall runHook postInstall
''; '';
enableParallelBuilding = true; enableParallelBuilding = true;
meta = with lib; { meta = with lib; {
description = "CPU core parking for Snapdragon X Elite (x1e80100)"; description = "Trigger EC hard reset via SSAM for Surface Laptop 7";
license = licenses.gpl2Only; license = licenses.gpl2Only;
platforms = platforms.linux; platforms = platforms.linux;
}; };
}; };
ec-reboot = pkgs.stdenv.mkDerivation { platform-profile = pkgs.stdenv.mkDerivation {
pname = "ec-reboot"; pname = "platform-profile-no-acpi";
version = "0.1.0-${kernel.version}"; inherit (kernel)
src = ./kernel/modules/ec-reboot; src
hardeningDisable = [ version
"pic" postPatch
"format" nativeBuildInputs
]; ;
nativeBuildInputs = kernel.moduleBuildDependencies ++ [ pkgs.kmod ]; kernel_dev = kernel.dev;
makeFlags = [ kernelVersion = kernel.modDirVersion;
"KERNELRELEASE=${kernel.modDirVersion}" patches = [
"KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" ./kernel/modules/platform-profile/platform-profile-no-acpi.patch
"INSTALL_MOD_PATH=$(out)" ];
]; buildPhase = ''
buildPhase = '' BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build
runHook preBuild cp $BUILT_KERNEL/Module.symvers .
make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \ cp $BUILT_KERNEL/.config .
M=$(pwd) \ cp $kernel_dev/vmlinux .
ARCH=${pkgs.stdenv.hostPlatform.linuxArch} \ make "-j$NIX_BUILD_CORES" modules_prepare
modules make "-j$NIX_BUILD_CORES" M=drivers/acpi modules
runHook postBuild '';
''; installPhase = ''
installPhase = '' make \
runHook preInstall INSTALL_MOD_PATH="$out" \
install -D -m 644 ec-reboot.ko $out/lib/modules/${kernel.modDirVersion}/extra/ec-reboot.ko XZ="xz -T$NIX_BUILD_CORES" \
runHook postInstall M="drivers/acpi" \
''; modules_install
enableParallelBuilding = true; '';
meta = with lib; { meta = with lib; {
description = "Trigger EC hard reset via SSAM for Surface Laptop 7"; description = "Platform profile module patched for DT-based systems";
license = licenses.gpl2Only; license = licenses.gpl2Only;
platforms = platforms.linux; platforms = platforms.linux;
}; };
}; };
platform-profile = pkgs.stdenv.mkDerivation { msm-vrr = pkgs.stdenv.mkDerivation {
pname = "platform-profile-no-acpi"; pname = "msm-vrr";
inherit (kernel) inherit (kernel)
src src
version version
postPatch postPatch
nativeBuildInputs nativeBuildInputs
; ;
kernel_dev = kernel.dev; kernel_dev = kernel.dev;
kernelVersion = kernel.modDirVersion; kernelVersion = kernel.modDirVersion;
patches = [ patches = [
./kernel/modules/platform-profile/platform-profile-no-acpi.patch ./kernel/modules/msm-vrr/msm-vrr-avr.patch
]; ];
buildPhase = '' buildPhase = ''
BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build
cp $BUILT_KERNEL/Module.symvers . cp $BUILT_KERNEL/Module.symvers .
cp $BUILT_KERNEL/.config . cp $BUILT_KERNEL/.config .
cp $kernel_dev/vmlinux . cp $kernel_dev/vmlinux .
make "-j$NIX_BUILD_CORES" modules_prepare make "-j$NIX_BUILD_CORES" modules_prepare
make "-j$NIX_BUILD_CORES" M=drivers/acpi modules make "-j$NIX_BUILD_CORES" M=drivers/gpu/drm/msm modules
''; '';
installPhase = '' installPhase = ''
make \ install -D -m 644 drivers/gpu/drm/msm/msm.ko \
INSTALL_MOD_PATH="$out" \ $out/lib/modules/${kernel.modDirVersion}/extra/msm.ko
XZ="xz -T$NIX_BUILD_CORES" \ '';
M="drivers/acpi" \ meta = with lib; {
modules_install description = "MSM DRM with VRR (24-120Hz) for the eDP panel";
''; license = licenses.gpl2Only;
meta = with lib; { platforms = platforms.linux;
description = "Platform profile module patched for DT-based systems"; };
license = licenses.gpl2Only; };
platforms = platforms.linux; in
};
};
in
{ {
options.x1e = { options.x1e = {
cpuParking = lib.mkEnableOption "CPU core parking for Snapdragon X Elite"; cpuParking = lib.mkEnableOption "CPU core parking for Snapdragon X Elite";
@@ -260,12 +296,12 @@ let
spi-geni-qcom-qspi spi-geni-qcom-qspi
ath12k-norfkill ath12k-norfkill
platform-profile platform-profile
msm-vrr
] ]
++ lib.optional config.x1e.ecReboot ec-reboot ++ lib.optional config.x1e.ecReboot ec-reboot
++ lib.optional config.x1e.cpuParking cpu-parking; ++ lib.optional config.x1e.cpuParking cpu-parking;
boot.kernelModules = boot.kernelModules =
lib.optional config.x1e.ecReboot "ec_reboot" lib.optional config.x1e.ecReboot "ec_reboot" ++ lib.optional config.x1e.cpuParking "cpu_parking";
++ lib.optional config.x1e.cpuParking "cpu_parking";
}; };
} }
+4 -4
View File
@@ -4,13 +4,13 @@
kernelPackages = kernelPackages =
let let
linux_x1e = pkgs.buildLinux rec { linux_x1e = pkgs.buildLinux rec {
version = "7.1.0-rc1"; version = "7.1.0";
modDirVersion = "7.1.0-rc1"; modDirVersion = "7.1.0";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "torvalds"; owner = "torvalds";
repo = "linux"; repo = "linux";
rev = "254f49634ee16a731174d2ae34bc50bd5f45e731"; # v7.1-rc1 rev = "8cd9520d35a6c38db6567e97dd93b1f11f185dc6"; # v7.1
hash = "sha256-88uBvJ2fZEWUAyMJZRNEFBZZPWaCp5O+KhTGa8u4EQw="; hash = "sha256-bKQiHEhaxinMh2ykjR/thBzkH1ts08IHLSg19BbvdaU=";
}; };
ignoreConfigErrors = true; ignoreConfigErrors = true;
structuredExtraConfig = with lib.kernel; { structuredExtraConfig = with lib.kernel; {
+288
View File
@@ -0,0 +1,288 @@
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h 2026-05-29 11:03:42.924716071 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h 2026-05-29 21:59:52.331868636 +0400
@@ -314,6 +314,7 @@
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25),
+ .features = BIT(DPU_INTF_AVR),
}, {
.name = "intf_1", .id = INTF_1,
.base = 0x35000, .len = 0x300,
@@ -348,6 +349,7 @@
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 20),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 21),
+ .features = BIT(DPU_INTF_AVR),
}, {
.name = "intf_5", .id = INTF_5,
.base = 0x39000, .len = 0x280,
@@ -356,6 +358,7 @@
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 22),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 23),
+ .features = BIT(DPU_INTF_AVR),
}, {
.name = "intf_6", .id = INTF_6,
.base = 0x3A000, .len = 0x280,
@@ -364,6 +367,7 @@
.prog_fetch_lines_worst_case = 24,
.intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16),
.intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17),
+ .features = BIT(DPU_INTF_AVR),
}, {
.name = "intf_7", .id = INTF_7,
.base = 0x3b000, .len = 0x280,
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 2026-05-29 11:03:40.286201235 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 2026-05-29 21:59:52.333730506 +0400
@@ -1508,6 +1508,9 @@
(!clone_mode_requested && clone_mode_enabled))
new_crtc_state->mode_changed = true;
+ if (new_crtc_state->vrr_enabled != old_crtc_state->vrr_enabled)
+ new_crtc_state->mode_changed = true;
+
return 0;
}
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 2026-05-29 11:03:39.718213467 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 2026-05-29 21:59:52.334011092 +0400
@@ -1268,6 +1268,20 @@
}
phys->cached_mode = crtc_state->adjusted_mode;
+
+ phys->vrr_enabled = false;
+ phys->vrr_min_fps = 0;
+ if (crtc_state->vrr_enabled && conn_state->connector) {
+ const struct drm_monitor_range_info *range =
+ &conn_state->connector->display_info.monitor_range;
+ u32 mode_fps = drm_mode_vrefresh(&crtc_state->adjusted_mode);
+
+ if (range->min_vfreq && range->min_vfreq < mode_fps) {
+ phys->vrr_enabled = true;
+ phys->vrr_min_fps = range->min_vfreq;
+ }
+ }
+
if (phys->ops.atomic_mode_set)
phys->ops.atomic_mode_set(phys, crtc_state, conn_state);
}
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 2026-05-29 11:11:43.623735790 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 2026-05-29 21:59:52.334868630 +0400
@@ -198,6 +198,8 @@
wait_queue_head_t pending_kickoff_wq;
unsigned int irq[INTR_IDX_MAX];
bool has_intf_te;
+ bool vrr_enabled;
+ u32 vrr_min_fps;
};
static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 2026-05-29 11:03:42.399672045 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 2026-05-29 21:59:52.336293281 +0400
@@ -314,6 +314,18 @@
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
&timing_params, fmt);
+
+ if (phys_enc->vrr_enabled && phys_enc->hw_intf->ops.setup_avr) {
+ struct dpu_hw_intf_avr_params avr = {
+ .default_fps = drm_mode_vrefresh(&mode),
+ .min_fps = phys_enc->vrr_min_fps,
+ };
+
+ phys_enc->hw_intf->ops.setup_avr(phys_enc->hw_intf,
+ &timing_params, &avr);
+ phys_enc->hw_intf->ops.avr_ctrl(phys_enc->hw_intf, true, false);
+ }
+
phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
/* setup which pp blk will connect to this intf */
@@ -664,6 +676,9 @@
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
phys_enc->enable_state = DPU_ENC_ENABLED;
}
+
+ if (phys_enc->vrr_enabled && phys_enc->hw_intf->ops.avr_trigger)
+ phys_enc->hw_intf->ops.avr_trigger(phys_enc->hw_intf);
}
static void dpu_encoder_phys_vid_irq_enable(struct dpu_encoder_phys *phys_enc)
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 2026-05-29 11:03:41.855674728 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 2026-05-29 21:59:52.336489789 +0400
@@ -150,6 +150,11 @@
DPU_DSC_MAX
};
+enum {
+ DPU_INTF_AVR = 0x1,
+ DPU_INTF_MAX
+};
+
/**
* MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
* @name: string name for debug purposes
@@ -519,6 +524,7 @@
unsigned int intr_underrun;
unsigned int intr_vsync;
unsigned int intr_tear_rd_ptr;
+ unsigned long features;
};
/**
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 2026-05-29 11:03:40.787734617 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 2026-05-29 21:59:52.336679956 +0400
@@ -77,6 +77,9 @@
#define INTF_AVR_MODE 0x274
#define INTF_AVR_TRIGGER 0x278
#define INTF_AVR_VTOTAL 0x27C
+
+#define INTF_AVR_CONTROL_ENABLE BIT(0)
+#define INTF_AVR_MODE_ONESHOT (BIT(0) | BIT(8))
#define INTF_TEAR_MDP_VSYNC_SEL 0x280
#define INTF_TEAR_TEAR_CHECK_EN 0x284
#define INTF_TEAR_SYNC_CONFIG_VSYNC 0x288
@@ -585,6 +588,47 @@
DPU_REG_WRITE(&intf->hw, INTF_CONFIG2, intf_cfg2);
}
+static void dpu_hw_intf_setup_avr(struct dpu_hw_intf *intf,
+ const struct dpu_hw_intf_timing_params *p,
+ const struct dpu_hw_intf_avr_params *avr)
+{
+ struct dpu_hw_blk_reg_map *c = &intf->hw;
+ u32 hsync_period, vsync_period, add_porches = 0, avr_vtotal;
+ u32 diff_fps;
+
+ if (!avr->min_fps || !avr->default_fps || avr->min_fps > avr->default_fps)
+ return;
+
+ diff_fps = avr->default_fps - avr->min_fps;
+
+ hsync_period = p->hsync_pulse_width + p->h_back_porch +
+ p->width + p->h_front_porch;
+ vsync_period = p->vsync_pulse_width + p->v_back_porch +
+ p->height + p->v_front_porch;
+
+ if (diff_fps)
+ add_porches = mult_frac(vsync_period, diff_fps, avr->min_fps);
+
+ avr_vtotal = (vsync_period + add_porches) * hsync_period;
+
+ DPU_REG_WRITE(c, INTF_AVR_VTOTAL, avr_vtotal);
+}
+
+static void dpu_hw_intf_avr_ctrl(struct dpu_hw_intf *intf, bool enable, bool oneshot)
+{
+ struct dpu_hw_blk_reg_map *c = &intf->hw;
+ u32 avr_ctrl = enable ? INTF_AVR_CONTROL_ENABLE : 0;
+ u32 avr_mode = (enable && oneshot) ? INTF_AVR_MODE_ONESHOT : 0;
+
+ DPU_REG_WRITE(c, INTF_AVR_CONTROL, avr_ctrl);
+ DPU_REG_WRITE(c, INTF_AVR_MODE, avr_mode);
+}
+
+static void dpu_hw_intf_avr_trigger(struct dpu_hw_intf *intf)
+{
+ DPU_REG_WRITE(&intf->hw, INTF_AVR_TRIGGER, 0x1);
+}
+
/**
* dpu_hw_intf_init() - Initializes the INTF driver for the passed
* interface catalog entry.
@@ -652,5 +696,11 @@
if (mdss_rev->core_major_ver >= 7)
c->ops.program_intf_cmd_cfg = dpu_hw_intf_program_intf_cmd_cfg;
+ if (cfg->features & BIT(DPU_INTF_AVR)) {
+ c->ops.setup_avr = dpu_hw_intf_setup_avr;
+ c->ops.avr_ctrl = dpu_hw_intf_avr_ctrl;
+ c->ops.avr_trigger = dpu_hw_intf_avr_trigger;
+ }
+
return c;
}
diff -ruN a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h 2026-05-29 11:03:41.261180349 +0400
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h 2026-05-29 21:59:52.337013151 +0400
@@ -37,6 +37,11 @@
bool compression_en;
};
+struct dpu_hw_intf_avr_params {
+ u32 default_fps;
+ u32 min_fps;
+};
+
struct dpu_hw_intf_prog_fetch {
u8 enable;
/* vsync counter for the front porch pixel line */
@@ -111,6 +116,14 @@
void (*program_intf_cmd_cfg)(struct dpu_hw_intf *intf,
struct dpu_hw_intf_cmd_mode_cfg *cmd_mode_cfg);
+
+ void (*setup_avr)(struct dpu_hw_intf *intf,
+ const struct dpu_hw_intf_timing_params *p,
+ const struct dpu_hw_intf_avr_params *avr);
+
+ void (*avr_ctrl)(struct dpu_hw_intf *intf, bool enable, bool oneshot);
+
+ void (*avr_trigger)(struct dpu_hw_intf *intf);
};
struct dpu_hw_intf {
diff -ruN a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c 2026-05-29 11:03:37.530261047 +0400
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c 2026-05-29 21:59:52.337233654 +0400
@@ -1639,6 +1639,9 @@
if (drm_dp_max_downspread(dpcd))
encoding[0] |= DP_SPREAD_AMP_0_5;
+ if (dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_MSA_TIMING_PAR_IGNORED)
+ encoding[0] |= DP_MSA_TIMING_PAR_IGNORE_EN;
+
/* config DOWNSPREAD_CTRL and MAIN_LINK_CHANNEL_CODING_SET */
drm_dp_dpcd_write(ctrl->aux, DP_DOWNSPREAD_CTRL, encoding, 2);
diff -ruN a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
--- a/drivers/gpu/drm/msm/dp/dp_drm.c 2026-05-29 11:03:38.667667124 +0400
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c 2026-05-29 21:59:52.337393023 +0400
@@ -376,6 +376,8 @@
if (!msm_dp_display->is_edp)
drm_connector_attach_dp_subconnector_property(connector);
+ drm_connector_attach_vrr_capable_property(connector);
+
drm_connector_attach_encoder(connector, encoder);
return connector;
diff -ruN a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
--- a/drivers/gpu/drm/msm/dp/dp_panel.c 2026-05-29 11:03:39.173225245 +0400
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c 2026-05-29 21:59:52.337516414 +0400
@@ -289,6 +289,17 @@
}
}
+ if (connector->vrr_capable_property) {
+ const struct drm_monitor_range_info *range =
+ &connector->display_info.monitor_range;
+ bool capable = range->min_vfreq && range->max_vfreq &&
+ range->min_vfreq < range->max_vfreq &&
+ (msm_dp_panel->dpcd[DP_DOWN_STREAM_PORT_COUNT] &
+ DP_MSA_TIMING_PAR_IGNORED);
+
+ drm_connector_set_vrr_capable_property(connector, capable);
+ }
+
end:
return rc;
}