From 29b0eeb0dcfff1949658226e42ed5876734c436f Mon Sep 17 00:00:00 2001 From: Asuna Yang Date: Thu, 4 Dec 2025 08:54:51 +0100 Subject: [PATCH 01/67] FROMLIST: rust: export BINDGEN_TARGET from a separate Makefile A subsequent commit will add a new function `bindgen-option` to `scripts/Kconfig.include`. The bindgen backend requires the `--target` option for cross compiling, but variable `BINDGEN_TARGET` in `rust/Makefile` cannot be exported to `scripts/Kconfig.include`. Therefore, move this variable to a separate new `Makefile.rust` file and include it from `scripts/Makefile` to make the exported variable available for use in Kconfig. Place the include in the `need-compiler` branch to avoid including it in irrelevant make targets. Since the new file name is `Makefile.rust`, it matches an existing MAINTAINERS rule `scripts/*rust*`, so no modification to the MAINTAINERS file is needed. Signed-off-by: Asuna Yang Link: https://lore.kernel.org/r/20251204-gcc-rust-v5-v5-1-2d4f20d86c24@gmail.com Signed-off-by: Han Gao --- Makefile | 3 ++- rust/Makefile | 8 -------- scripts/Makefile.rust | 9 +++++++++ 3 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 scripts/Makefile.rust diff --git a/Makefile b/Makefile index 23cc6c39819b11..57807a5f3f6005 100644 --- a/Makefile +++ b/Makefile @@ -718,9 +718,10 @@ ifneq ($(findstring clang,$(CC_VERSION_TEXT)),) include $(srctree)/scripts/Makefile.clang endif +ifdef need-compiler +include $(srctree)/scripts/Makefile.rust # Include this also for config targets because some architectures need # cc-cross-prefix to determine CROSS_COMPILE. -ifdef need-compiler include $(srctree)/scripts/Makefile.compiler endif diff --git a/rust/Makefile b/rust/Makefile index 7842ad0a4ea726..ae7cbbd89da37d 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -300,14 +300,6 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ -fzero-init-padding-bits=% -mno-fdpic \ --param=% --param asan-% -fno-isolate-erroneous-paths-dereference -# Derived from `scripts/Makefile.clang`. -BINDGEN_TARGET_x86 := x86_64-linux-gnu -BINDGEN_TARGET_arm64 := aarch64-linux-gnu -BINDGEN_TARGET_arm := arm-linux-gnueabi -BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf -BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH)) -BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH)) - # All warnings are inhibited since GCC builds are very experimental, # many GCC warnings are not supported by Clang, they may only appear in # some configurations, with new GCC versions, etc. diff --git a/scripts/Makefile.rust b/scripts/Makefile.rust new file mode 100644 index 00000000000000..5c12b4b8c8b65f --- /dev/null +++ b/scripts/Makefile.rust @@ -0,0 +1,9 @@ +# Derived from `scripts/Makefile.clang`. +BINDGEN_TARGET_x86 := x86_64-linux-gnu +BINDGEN_TARGET_arm64 := aarch64-linux-gnu +BINDGEN_TARGET_arm := arm-linux-gnueabi +BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf +BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH)) +BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH)) + +export BINDGEN_TARGET From 8f7fb734e355e20c43ffe9952b5d3ea20401635e Mon Sep 17 00:00:00 2001 From: Asuna Yang Date: Thu, 4 Dec 2025 08:54:52 +0100 Subject: [PATCH 02/67] FROMLIST: rust: generate a fatal error if BINDGEN_TARGET is undefined Generate a friendly fatal error if the target triplet is undefined for bindgen, rather than having the compiler generate obscure error messages during the build stage. This piece of code is copied from `scripts/Makefile.clang`. Before this commit, error messages might look like: error: unknown argument: '-mno-riscv-attribute' error: unsupported argument 'medany' to option '-mcmodel=' for target 'unknown' error: unsupported option '-march=' for target '' error: unsupported option '-mno-save-restore' for target '' error: unknown target triple 'unknown' panicked at bindgen/ir/context.rs:562:15: libclang error; possible causes include: - Invalid flag syntax - Unrecognized flags - Invalid flag arguments - File I/O errors - Host vs. target architecture mismatch Acked-by: Miguel Ojeda Signed-off-by: Asuna Yang Link: https://lore.kernel.org/r/20251204-gcc-rust-v5-v5-2-2d4f20d86c24@gmail.com Signed-off-by: Han Gao --- scripts/Makefile.rust | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/Makefile.rust b/scripts/Makefile.rust index 5c12b4b8c8b65f..b219244cd05104 100644 --- a/scripts/Makefile.rust +++ b/scripts/Makefile.rust @@ -6,4 +6,8 @@ BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH)) BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH)) +ifeq ($(BINDGEN_TARGET),) +$(error add '--target=' option to scripts/Makefile.rust) +else export BINDGEN_TARGET +endif From d76faed5d097c15011d3bdfa64ee6e291a617e58 Mon Sep 17 00:00:00 2001 From: Asuna Yang Date: Thu, 4 Dec 2025 08:54:53 +0100 Subject: [PATCH 03/67] FROMLIST: rust: add a Kconfig function to test for support of bindgen options Add a new `bindgen-backend-option` Kconfig function to test whether the bindgen backend supports a given flag. A subsequent commit will use this function to test for RISC-V extension flags. Signed-off-by: Asuna Yang Link: https://lore.kernel.org/r/20251204-gcc-rust-v5-v5-3-2d4f20d86c24@gmail.com Signed-off-by: Han Gao --- scripts/Kconfig.include | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 33193ca6e8030e..bf940e68e4679a 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -75,3 +75,8 @@ rustc-llvm-version := $(shell,$(srctree)/scripts/rustc-llvm-version.sh $(RUSTC)) # If you are testing for unstable features, consider testing RUSTC_VERSION # instead, as features may have different completeness while available. rustc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(RUSTC) $(1) --crate-type=rlib /dev/null --out-dir=.tmp_$$ -o .tmp_$$/tmp.rlib) + +# $(bindgen-backend-option,) +# Return y if bindgen backend supports , n otherwise +# For now, the backend refers only to libclang, so more specifically, this function tests whether the given flag is recognized by the libclang used by bindgen. +bindgen-backend-option = $(success,trap "rm -f .tmp_$$.h" EXIT; touch .tmp_$$.h; $(BINDGEN) .tmp_$$.h -- --target=$(BINDGEN_TARGET) $(1)) From 3fb426e1c8e37aadf674a743da3ec4d3c4290313 Mon Sep 17 00:00:00 2001 From: Asuna Yang Date: Thu, 4 Dec 2025 08:54:54 +0100 Subject: [PATCH 04/67] FROMLIST: RISC-V: handle extension configs for bindgen, re-enable gcc + rust builds Commit 33549fcf37ec ("RISC-V: disallow gcc + rust builds") disabled GCC + Rust builds for RISC-V due to differences in extension handling compared to LLVM. This commit enables GCC + Rust builds again. Add `bindgen-option` conditions for the availability of libclang to the RISC-V extension Kconfig symbols that depend on the `cc-option` function. For Zicsr/Zifencei special handling, since LLVM/Clang always enables these two extensions, either don't pass them to `-march`, or pass them explicitly and Rust bindgen libclang must recognize them. Clang does not support `-mno-riscv-attribute` flag, filter it out to resolve error: unknown argument: '-mno-riscv-attribute'. Define `BINDGEN_TARGET_riscv` to pass the target triplet to Rust bindgen libclang for RISC-V to resolve error: unsupported argument 'medany' to option '-mcmodel=' for target 'unknown'. Update the documentation, GCC + Rust builds for RISC-V are now maintained. Acked-by: Miguel Ojeda Signed-off-by: Asuna Yang Link: https://lore.kernel.org/r/20251204-gcc-rust-v5-v5-4-2d4f20d86c24@gmail.com Signed-off-by: Han Gao --- Documentation/rust/arch-support.rst | 2 +- arch/riscv/Kconfig | 35 ++++++++++++++++++++++++++++- rust/Makefile | 3 ++- scripts/Makefile.rust | 1 + 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Documentation/rust/arch-support.rst b/Documentation/rust/arch-support.rst index 6e6a515d08991a..5282e0e174e8de 100644 --- a/Documentation/rust/arch-support.rst +++ b/Documentation/rust/arch-support.rst @@ -18,7 +18,7 @@ Architecture Level of support Constraints ``arm`` Maintained ARMv7 Little Endian only. ``arm64`` Maintained Little Endian only. ``loongarch`` Maintained \- -``riscv`` Maintained ``riscv64`` and LLVM/Clang only. +``riscv`` Maintained ``riscv64`` only. ``um`` Maintained \- ``x86`` Maintained ``x86_64`` only. ============= ================ ============================================== diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index fadec20b87a8e3..9a56063966460f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -193,7 +193,7 @@ config RISCV select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RETHOOK if !XIP_KERNEL select HAVE_RSEQ - select HAVE_RUST if RUSTC_SUPPORTS_RISCV && CC_IS_CLANG + select HAVE_RUST if RUSTC_SUPPORTS_RISCV && TOOLCHAIN_MATCHES_ZICSR_ZIFENCEI select HAVE_SAMPLE_FTRACE_DIRECT select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_STACKPROTECTOR @@ -617,6 +617,8 @@ config TOOLCHAIN_HAS_V depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32imv) depends on LD_IS_LLD || LD_VERSION >= 23800 depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64imv) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32imv) config RISCV_ISA_V bool "Vector extension support" @@ -681,6 +683,8 @@ config TOOLCHAIN_HAS_ZABHA depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64ima_zabha) depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zabha) depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zabha) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zabha) config RISCV_ISA_ZABHA bool "Zabha extension support for atomic byte/halfword operations" @@ -699,6 +703,8 @@ config TOOLCHAIN_HAS_ZACAS depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64ima_zacas) depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zacas) depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zacas) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zacas) config RISCV_ISA_ZACAS bool "Zacas extension support for atomic CAS" @@ -717,6 +723,8 @@ config TOOLCHAIN_HAS_ZBB depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zbb) depends on LD_IS_LLD || LD_VERSION >= 23900 depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zbb) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zbb) # This symbol indicates that the toolchain supports all v1.0 vector crypto # extensions, including Zvk*, Zvbb, and Zvbc. LLVM added all of these at once. @@ -732,6 +740,8 @@ config TOOLCHAIN_HAS_ZBA depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zba) depends on LD_IS_LLD || LD_VERSION >= 23900 depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zba) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zba) config RISCV_ISA_ZBA bool "Zba extension support for bit manipulation instructions" @@ -767,6 +777,8 @@ config TOOLCHAIN_HAS_ZBC depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zbc) depends on LD_IS_LLD || LD_VERSION >= 23900 depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zbc) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zbc) config RISCV_ISA_ZBC bool "Zbc extension support for carry-less multiplication instructions" @@ -790,6 +802,8 @@ config TOOLCHAIN_HAS_ZBKB depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zbkb) depends on LD_IS_LLD || LD_VERSION >= 23900 depends on AS_HAS_OPTION_ARCH + depends on !RUST || !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zbkb) + depends on !RUST || !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zbkb) config RISCV_ISA_ZBKB bool "Zbkb extension support for bit manipulation instructions" @@ -877,6 +891,25 @@ config TOOLCHAIN_NEEDS_OLD_ISA_SPEC versions of clang and GCC to be passed to GAS, which has the same result as passing zicsr and zifencei to -march. +config RUST_BINDGEN_HAS_ZICSR_ZIFENCEI + def_bool y + depends on !64BIT || $(bindgen-backend-option,-mabi=lp64 -march=rv64ima_zicsr_zifencei) + depends on !32BIT || $(bindgen-backend-option,-mabi=ilp32 -march=rv32ima_zicsr_zifencei) + +config TOOLCHAIN_MATCHES_ZICSR_ZIFENCEI + def_bool y + # https://github.com/llvm/llvm-project/commit/22e199e6afb1263c943c0c0d4498694e15bf8a16 + depends on TOOLCHAIN_NEEDS_OLD_ISA_SPEC || !TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI || RUST_BINDGEN_HAS_ZICSR_ZIFENCEI + help + LLVM/Clang >= 17.0.0 starts recognizing Zicsr/Zifencei in -march, passing + them to -march doesn't generate an error anymore, and passing them or not + doesn't have any real difference, it still follows ISA before version + 20190608 - Zicsr/Zifencei are included in base ISA. + + The current latest version of LLVM/Clang still does not require explicit + Zicsr/Zifencei to enable these two extensions, Clang just accepts them in + -march and then silently ignores them. + config FPU bool "FPU support" default y diff --git a/rust/Makefile b/rust/Makefile index ae7cbbd89da37d..1f209e6025e4ae 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -298,7 +298,8 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ -fno-inline-functions-called-once -fsanitize=bounds-strict \ -fstrict-flex-arrays=% -fmin-function-alignment=% \ -fzero-init-padding-bits=% -mno-fdpic \ - --param=% --param asan-% -fno-isolate-erroneous-paths-dereference + --param=% --param asan-% -fno-isolate-erroneous-paths-dereference \ + -mno-riscv-attribute # All warnings are inhibited since GCC builds are very experimental, # many GCC warnings are not supported by Clang, they may only appear in diff --git a/scripts/Makefile.rust b/scripts/Makefile.rust index b219244cd05104..cee28a6048302a 100644 --- a/scripts/Makefile.rust +++ b/scripts/Makefile.rust @@ -3,6 +3,7 @@ BINDGEN_TARGET_x86 := x86_64-linux-gnu BINDGEN_TARGET_arm64 := aarch64-linux-gnu BINDGEN_TARGET_arm := arm-linux-gnueabi BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf +BINDGEN_TARGET_riscv := riscv64-linux-gnu BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH)) BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH)) From 0bcd40ec0b77df08f8f87b720dc2d75833f2bfc3 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Sun, 21 Dec 2025 00:33:38 +0800 Subject: [PATCH 05/67] FROMLIST: drm/radeon: bypass no_64bit_msi with new msi64 parameter Sophgo SG2042's MSI driver lacks 32-bit MSI support. Added a msi64 parameter to skip the limitation and force 64-bit MSI. Link: https://lore.kernel.org/r/20251220163338.3852399-1-gaohan@iscas.ac.cn Signed-off-by: Han Gao --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index cc0bc138f56b06..392a6f61e51e4c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -121,6 +121,7 @@ extern int radeon_uvd; extern int radeon_vce; extern int radeon_si_support; extern int radeon_cik_support; +extern int radeon_msi64; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 8ed93481f714c1..1edbc7a6d8aa46 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -249,6 +249,10 @@ int radeon_cik_support = 0; MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled, 0 = disabled (default))"); module_param_named(cik_support, radeon_cik_support, int, 0444); +int radeon_msi64; +MODULE_PARM_DESC(msi64, "MSI64 support (1 = enabled, 0 = disabled)"); +module_param_named(msi64, radeon_msi64, int, 0444); + static const struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index d4ad1fa8264542..a9226c456eea11 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -251,7 +251,7 @@ static bool radeon_msi_ok(struct radeon_device *rdev) * of address for "64-bit" MSIs which breaks on some platforms, notably * IBM POWER servers, so we limit them */ - if (rdev->family < CHIP_BONAIRE) { + if (rdev->family < CHIP_BONAIRE && !radeon_msi64) { dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n"); rdev->pdev->no_64bit_msi = 1; } From 778bb75b021ecf3498d1d5d49918160f97554086 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Sun, 21 Dec 2025 01:05:01 +0800 Subject: [PATCH 06/67] FROMLIST: ALSA: hda: intel: Introduce msi64 parameter to override 64-bit MSI restriction Sophgo SG2042 MSI driver does not support 32-bit MSI. Introduce an 'msi64' kernel parameter to bypass NO_MSI64 for ATI/HDMI. Link: https://lore.kernel.org/r/20251220170501.3972438-1-gaohan@iscas.ac.cn Signed-off-by: Han Gao --- sound/hda/controllers/intel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c index a19258c95886c4..14bc1c8cdf1680 100644 --- a/sound/hda/controllers/intel.c +++ b/sound/hda/controllers/intel.c @@ -121,6 +121,7 @@ static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = #endif static bool dmic_detect = 1; static bool ctl_dev_id = IS_ENABLED(CONFIG_SND_HDA_CTL_DEV_ID) ? 1 : 0; +static bool msi64; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -161,6 +162,8 @@ MODULE_PARM_DESC(dmic_detect, "Allow DSP driver selection (bypass this driver) " "deprecated, use snd-intel-dspcfg.dsp_driver option instead"); module_param(ctl_dev_id, bool, 0444); MODULE_PARM_DESC(ctl_dev_id, "Use control device identifier (based on codec address)."); +module_param(msi64, bool, 0444); +MODULE_PARM_DESC(msi64, "Force use msi 64bit."); #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); @@ -1903,7 +1906,7 @@ static int azx_first_init(struct azx *chip) chip->gts_present = true; #endif - if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { + if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64 && !msi64) { dev_dbg(card->dev, "Disabling 64bit MSI\n"); pci->no_64bit_msi = true; } From 9f926ded91a0c29ce8e53da6085706fcf159f842 Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Fri, 12 Dec 2025 13:47:17 -0500 Subject: [PATCH 07/67] UPSTREAM: lib/crypto: riscv: Add poly1305-core.S to .gitignore poly1305-core.S is an auto-generated file, so it should be ignored. Fixes: bef9c7559869 ("lib/crypto: riscv/poly1305: Import OpenSSL/CRYPTOGAMS implementation") Cc: stable@vger.kernel.org Signed-off-by: Charles Mirabile Link: https://lore.kernel.org/r/20251212184717.133701-1-cmirabil@redhat.com Signed-off-by: Eric Biggers (cherry picked from commit 5a0b1882506858b12cc77f0e2439a5f3c5052761) Signed-off-by: Han Gao --- lib/crypto/riscv/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 lib/crypto/riscv/.gitignore diff --git a/lib/crypto/riscv/.gitignore b/lib/crypto/riscv/.gitignore new file mode 100644 index 00000000000000..0d47d4f21c6de9 --- /dev/null +++ b/lib/crypto/riscv/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +poly1305-core.S From eea02759dff8703c66e706d55b6049b73a18715e Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:39:45 +0800 Subject: [PATCH 08/67] Revert "FROMLIST: drm/ttm: add pgprot handling for RISC-V" This reverts commit 2fba856f6ffaaeb609696e53fd2b618c6b8fa2b5. --- drivers/gpu/drm/ttm/ttm_module.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c index aa137ead5cc596..b3fffe7b5062a9 100644 --- a/drivers/gpu/drm/ttm/ttm_module.c +++ b/drivers/gpu/drm/ttm/ttm_module.c @@ -74,8 +74,7 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp) #endif /* CONFIG_UML */ #endif /* __i386__ || __x86_64__ */ #if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \ - defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) || \ - defined(__riscv) + defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) if (caching == ttm_write_combined) tmp = pgprot_writecombine(tmp); else From 1f11404034c700e2c82e66f570a929144328002b Mon Sep 17 00:00:00 2001 From: Han Gao Date: Fri, 5 Dec 2025 10:42:07 +0800 Subject: [PATCH 09/67] UPSTREAM: drm/ttm: add pgprot handling for RISC-V MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RISC-V Svpbmt privileged extension provides support for overriding page memory coherency attributes, and, along with vendor extensions like Xtheadmae, supports pgprot_{writecombine,noncached} on RISC-V. Adapt the codepath that maps ttm_write_combined to pgprot_writecombine and ttm_noncached to pgprot_noncached to RISC-V, to allow proper page access attributes. Signed-off-by: Icenowy Zheng Tested-by: Han Gao Acked-by: Christian König Signed-off-by: Christian König Link: https://lore.kernel.org/r/20251020053523.731353-1-uwu@icenowy.me (cherry picked from commit 4f9ffd2c80a2fa09dcc8dfa0482cb7e0fb6fcf6c) Signed-off-by: Han Gao --- drivers/gpu/drm/ttm/ttm_module.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c index b3fffe7b5062a9..aa137ead5cc596 100644 --- a/drivers/gpu/drm/ttm/ttm_module.c +++ b/drivers/gpu/drm/ttm/ttm_module.c @@ -74,7 +74,8 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp) #endif /* CONFIG_UML */ #endif /* __i386__ || __x86_64__ */ #if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \ - defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) + defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) || \ + defined(__riscv) if (caching == ttm_write_combined) tmp = pgprot_writecombine(tmp); else From 181733bf758bf2a4bfd7c26ab7493d9e0be03ae3 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:42 +0800 Subject: [PATCH 10/67] Revert "FROMLIST: riscv: dts: sophgo: Enable SPI NOR node for SG2042_EVB_V2" This reverts commit cee37bbedf145d4313baf46908281787daa75c15. --- arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts index b2ceae2d8829ec..0cd0dc0f537c14 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts @@ -238,18 +238,6 @@ status = "okay"; }; -&spifmc1 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <1>; - }; -}; - &uart0 { pinctrl-0 = <&uart0_cfg>; pinctrl-names = "default"; From 181f4842a9ff4fc47e4b24cf44545c80d9a00614 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:44 +0800 Subject: [PATCH 11/67] Revert "FROMLIST: riscv: dts: sophgo: Enable SPI NOR node for SG2042_EVB_V1" This reverts commit 5f6021f5e1938d9b70c9dae267c9fe577f823e87. --- arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts | 24 -------------------- 1 file changed, 24 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts index b116dfa904cd98..a186d036cf3606 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts @@ -250,30 +250,6 @@ status = "okay"; }; -&spifmc0 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <1>; - }; -}; - -&spifmc1 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <1>; - }; -}; - &uart0 { pinctrl-0 = <&uart0_cfg>; pinctrl-names = "default"; From 4e77d2b8de7ba504ea9ca89c9d3cf1b097dc96de Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:45 +0800 Subject: [PATCH 12/67] Revert "FROMLIST: riscv: dts: sophgo: Enable SPI NOR node for PioneerBox" This reverts commit 8857c2eacf198a5274804c890b9f039634f7ac2b. --- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts index 54d8386bf9c0ff..c4d5f8d7d4ad3f 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts @@ -150,30 +150,6 @@ status = "okay"; }; -&spifmc0 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <1>; - }; -}; - -&spifmc1 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <1>; - }; -}; - &uart0 { pinctrl-0 = <&uart0_cfg>; pinctrl-names = "default"; From cf9c3b85c21abed5dcb6b9a61b14238d4cefc843 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:47 +0800 Subject: [PATCH 13/67] Revert "FROMLIST: riscv: dts: sophgo: Add SPI NOR node for SG2042" This reverts commit defa6ffd5eafdec8745479098b7e8e2fb1933415. --- arch/riscv/boot/dts/sophgo/sg2042.dtsi | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi index e0e805c86b32a6..e3497b5cad1df8 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi +++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi @@ -68,30 +68,6 @@ interrupt-parent = <&intc>; ranges; - spifmc0: spi@7000180000 { - compatible = "sophgo,sg2042-spifmc-nor"; - reg = <0x70 0x00180000 0x0 0x1000000>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkgen GATE_CLK_AHB_SF>; - interrupt-parent = <&intc>; - interrupts = <108 IRQ_TYPE_LEVEL_HIGH>; - resets = <&rstgen RST_SF0>; - status = "disabled"; - }; - - spifmc1: spi@7002180000 { - compatible = "sophgo,sg2042-spifmc-nor"; - reg = <0x70 0x02180000 0x0 0x1000000>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clkgen GATE_CLK_AHB_SF>; - interrupt-parent = <&intc>; - interrupts = <109 IRQ_TYPE_LEVEL_HIGH>; - resets = <&rstgen RST_SF1>; - status = "disabled"; - }; - i2c0: i2c@7030005000 { compatible = "snps,designware-i2c"; reg = <0x70 0x30005000 0x0 0x1000>; From e4aa4d5df2fb3cff6e3f2ab2abe00a21781c400d Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:48 +0800 Subject: [PATCH 14/67] Revert "FROMLIST: riscv: sophgo: dts: enable PCIe for SG2042_EVB_V2.0" This reverts commit 831ecc408a03e89dba61e55fa6ca8f2bcd23362d. --- arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts index 0cd0dc0f537c14..46980e41b886ce 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts @@ -152,18 +152,6 @@ }; }; -&pcie_rc0 { - status = "okay"; -}; - -&pcie_rc1 { - status = "okay"; -}; - -&pcie_rc2 { - status = "okay"; -}; - &pinctrl { emmc_cfg: sdhci-emmc-cfg { sdhci-emmc-wp-pins { From 593ab8b20173d769c40e48f9170e509743a3d3fb Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:50 +0800 Subject: [PATCH 15/67] Revert "FROMLIST: riscv: sophgo: dts: enable PCIe for SG2042_EVB_V1.X" This reverts commit 84fe19a716abe9d63cb80a263b0ff581a53ed265. --- arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts index a186d036cf3606..3320bc1dd2c66a 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts @@ -164,18 +164,6 @@ }; }; -&pcie_rc0 { - status = "okay"; -}; - -&pcie_rc1 { - status = "okay"; -}; - -&pcie_rc2 { - status = "okay"; -}; - &pinctrl { emmc_cfg: sdhci-emmc-cfg { sdhci-emmc-wp-pins { From 6c1d0cf3df52c0cbf94c9872650ca07e1ac80589 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:41:52 +0800 Subject: [PATCH 16/67] Revert "FROMLIST: riscv: sophgo: dts: enable PCIe for PioneerBox" This reverts commit 32703ca79bed9e75521cbb87a2c3e9d206bc3744. --- arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts index c4d5f8d7d4ad3f..ef3a602172b1e5 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts @@ -128,18 +128,6 @@ }; }; -&pcie_rc0 { - status = "okay"; -}; - -&pcie_rc2 { - status = "okay"; -}; - -&pcie_rc3 { - status = "okay"; -}; - &sd { pinctrl-0 = <&sd_cfg>; pinctrl-names = "default"; From bf25bc20225d16a4a1dd6078f48f4e10acc7b0b2 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:42:04 +0800 Subject: [PATCH 17/67] Revert "FROMLIST: riscv: sophgo: dts: add PCIe controllers for SG2042" This reverts commit 4cda6dc1bd34e5a3243a62fcd0ad61f3367b1ac1. --- arch/riscv/boot/dts/sophgo/sg2042.dtsi | 88 -------------------------- 1 file changed, 88 deletions(-) diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi index e3497b5cad1df8..c5e49709b30882 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi +++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi @@ -240,94 +240,6 @@ #clock-cells = <1>; }; - pcie_rc0: pcie@7060000000 { - compatible = "sophgo,sg2042-pcie-host"; - device_type = "pci"; - reg = <0x70 0x60000000 0x0 0x00800000>, - <0x40 0x00000000 0x0 0x00001000>; - reg-names = "reg", "cfg"; - linux,pci-domain = <0>; - #address-cells = <3>; - #size-cells = <2>; - ranges = <0x01000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x00400000>, - <0x42000000 0x0 0xd0000000 0x40 0xd0000000 0x0 0x10000000>, - <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, - <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, - <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; - bus-range = <0x0 0xff>; - vendor-id = <0x1f1c>; - device-id = <0x2042>; - cdns,no-bar-match-nbits = <48>; - msi-parent = <&msi>; - status = "disabled"; - }; - - pcie_rc1: pcie@7060800000 { - compatible = "sophgo,sg2042-pcie-host"; - device_type = "pci"; - reg = <0x70 0x60800000 0x0 0x00800000>, - <0x44 0x00000000 0x0 0x00001000>; - reg-names = "reg", "cfg"; - linux,pci-domain = <1>; - #address-cells = <3>; - #size-cells = <2>; - ranges = <0x01000000 0x0 0xc0400000 0x44 0xc0400000 0x0 0x00400000>, - <0x42000000 0x0 0xd0000000 0x44 0xd0000000 0x0 0x10000000>, - <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, - <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, - <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; - bus-range = <0x0 0xff>; - vendor-id = <0x1f1c>; - device-id = <0x2042>; - cdns,no-bar-match-nbits = <48>; - msi-parent = <&msi>; - status = "disabled"; - }; - - pcie_rc2: pcie@7062000000 { - compatible = "sophgo,sg2042-pcie-host"; - device_type = "pci"; - reg = <0x70 0x62000000 0x0 0x00800000>, - <0x48 0x00000000 0x0 0x00001000>; - reg-names = "reg", "cfg"; - linux,pci-domain = <2>; - #address-cells = <3>; - #size-cells = <2>; - ranges = <0x01000000 0x0 0xc0800000 0x48 0xc0800000 0x0 0x00400000>, - <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, - <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, - <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, - <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; - bus-range = <0x0 0xff>; - vendor-id = <0x1f1c>; - device-id = <0x2042>; - cdns,no-bar-match-nbits = <48>; - msi-parent = <&msi>; - status = "disabled"; - }; - - pcie_rc3: pcie@7062800000 { - compatible = "sophgo,sg2042-pcie-host"; - device_type = "pci"; - reg = <0x70 0x62800000 0x0 0x00800000>, - <0x4c 0x00000000 0x0 0x00001000>; - reg-names = "reg", "cfg"; - linux,pci-domain = <3>; - #address-cells = <3>; - #size-cells = <2>; - ranges = <0x01000000 0x0 0xc0c00000 0x4c 0xc0c00000 0x0 0x00400000>, - <0x42000000 0x0 0xf8000000 0x4c 0xf8000000 0x0 0x04000000>, - <0x02000000 0x0 0xfc000000 0x4c 0xfc000000 0x0 0x04000000>, - <0x43000000 0x4e 0x00000000 0x4e 0x00000000 0x2 0x00000000>, - <0x03000000 0x4d 0x00000000 0x4d 0x00000000 0x1 0x00000000>; - bus-range = <0x0 0xff>; - vendor-id = <0x1f1c>; - device-id = <0x2042>; - cdns,no-bar-match-nbits = <48>; - msi-parent = <&msi>; - status = "disabled"; - }; - clint_mswi: interrupt-controller@7094000000 { compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi"; reg = <0x00000070 0x94000000 0x00000000 0x00004000>; From 9d162ec17d85acde44db255987270310e3f3a024 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Mon, 20 Oct 2025 11:33:43 +0800 Subject: [PATCH 18/67] UPSTREAM: riscv: sophgo: dts: add PCIe controllers for SG2042 Add PCIe controller nodes in DTS for Sophgo SG2042. Default they are disabled. Acked-by: Manivannan Sadhasivam Signed-off-by: Han Gao Signed-off-by: Chen Wang Link: https://lore.kernel.org/r/b34d819cd763482e0ecbc5c5ea721f0101d1f844.1760929111.git.unicorn_wang@outlook.com Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang (cherry picked from commit 4e27aca4881ace1e9a812fc2c88b33dd84e29993) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042.dtsi | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi index c5e49709b30882..85d8b89cf9fc91 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi +++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi @@ -240,6 +240,94 @@ #clock-cells = <1>; }; + pcie_rc0: pcie@7060000000 { + compatible = "sophgo,sg2042-pcie-host"; + device_type = "pci"; + reg = <0x70 0x60000000 0x0 0x00800000>, + <0x40 0x00000000 0x0 0x00001000>; + reg-names = "reg", "cfg"; + linux,pci-domain = <0>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x40 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x40 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, + <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, + <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; + bus-range = <0x0 0xff>; + vendor-id = <0x1f1c>; + device-id = <0x2042>; + cdns,no-bar-match-nbits = <48>; + msi-parent = <&msi>; + status = "disabled"; + }; + + pcie_rc1: pcie@7060800000 { + compatible = "sophgo,sg2042-pcie-host"; + device_type = "pci"; + reg = <0x70 0x60800000 0x0 0x00800000>, + <0x44 0x00000000 0x0 0x00001000>; + reg-names = "reg", "cfg"; + linux,pci-domain = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x44 0xc0400000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x44 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, + <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, + <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; + bus-range = <0x0 0xff>; + vendor-id = <0x1f1c>; + device-id = <0x2042>; + cdns,no-bar-match-nbits = <48>; + msi-parent = <&msi>; + status = "disabled"; + }; + + pcie_rc2: pcie@7062000000 { + compatible = "sophgo,sg2042-pcie-host"; + device_type = "pci"; + reg = <0x70 0x62000000 0x0 0x00800000>, + <0x48 0x00000000 0x0 0x00001000>; + reg-names = "reg", "cfg"; + linux,pci-domain = <2>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x48 0xc0800000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, + <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, + <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; + bus-range = <0x0 0xff>; + vendor-id = <0x1f1c>; + device-id = <0x2042>; + cdns,no-bar-match-nbits = <48>; + msi-parent = <&msi>; + status = "disabled"; + }; + + pcie_rc3: pcie@7062800000 { + compatible = "sophgo,sg2042-pcie-host"; + device_type = "pci"; + reg = <0x70 0x62800000 0x0 0x00800000>, + <0x4c 0x00000000 0x0 0x00001000>; + reg-names = "reg", "cfg"; + linux,pci-domain = <3>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x4c 0xc0c00000 0x0 0x00400000>, + <0x42000000 0x0 0xf8000000 0x4c 0xf8000000 0x0 0x04000000>, + <0x02000000 0x0 0xfc000000 0x4c 0xfc000000 0x0 0x04000000>, + <0x43000000 0x4e 0x00000000 0x4e 0x00000000 0x2 0x00000000>, + <0x03000000 0x4d 0x00000000 0x4d 0x00000000 0x1 0x00000000>; + bus-range = <0x0 0xff>; + vendor-id = <0x1f1c>; + device-id = <0x2042>; + cdns,no-bar-match-nbits = <48>; + msi-parent = <&msi>; + status = "disabled"; + }; + clint_mswi: interrupt-controller@7094000000 { compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi"; reg = <0x00000070 0x94000000 0x00000000 0x00004000>; From 273f982fe27902d538dc2fb12a2bed048221fb99 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Mon, 20 Oct 2025 11:34:05 +0800 Subject: [PATCH 19/67] UPSTREAM: riscv: sophgo: dts: enable PCIe for PioneerBox Enable PCIe controllers for PioneerBox, which uses SG2042 SoC. Signed-off-by: Chen Wang Link: https://lore.kernel.org/r/ec474c5eefb79626dd6a4d65454da9109aaf2f4d.1760929111.git.unicorn_wang@outlook.com Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang (cherry picked from commit b85ad0d06a19de95d41f91162389a1bbb461a405) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts index ef3a602172b1e5..c4d5f8d7d4ad3f 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts @@ -128,6 +128,18 @@ }; }; +&pcie_rc0 { + status = "okay"; +}; + +&pcie_rc2 { + status = "okay"; +}; + +&pcie_rc3 { + status = "okay"; +}; + &sd { pinctrl-0 = <&sd_cfg>; pinctrl-names = "default"; From 885ba32441f36c1a4ec4d88e32cedba1a1ecff88 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Mon, 20 Oct 2025 11:39:22 +0800 Subject: [PATCH 20/67] UPSTREAM: riscv: sophgo: dts: enable PCIe for SG2042_EVB_V1.X Enable PCIe controllers for Sophgo SG2042_EVB_V1.X board, which uses SG2042 SoC. Signed-off-by: Han Gao Signed-off-by: Chen Wang Link: https://lore.kernel.org/r/1ad96631cc9d9d7403a2bed5585d856fa101a2ef.1760929111.git.unicorn_wang@outlook.com Tested-by: Han Gao Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang (cherry picked from commit c6c215099e89b1eb71ed6592163ae5b530f4538e) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts index 3320bc1dd2c66a..a186d036cf3606 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts @@ -164,6 +164,18 @@ }; }; +&pcie_rc0 { + status = "okay"; +}; + +&pcie_rc1 { + status = "okay"; +}; + +&pcie_rc2 { + status = "okay"; +}; + &pinctrl { emmc_cfg: sdhci-emmc-cfg { sdhci-emmc-wp-pins { From 45b3c38648490490659f7dbcd5cb44fc08759ca1 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Mon, 20 Oct 2025 11:40:09 +0800 Subject: [PATCH 21/67] UPSTREAM: riscv: sophgo: dts: enable PCIe for SG2042_EVB_V2.0 Enable PCIe controllers for Sophgo SG2042_EVB_V2.0 board, which uses SG2042 SoC. Signed-off-by: Han Gao Signed-off-by: Chen Wang Link: https://lore.kernel.org/r/50a753f9b8cbd5a90b5b2df737f87fc77a9b33a7.1760929111.git.unicorn_wang@outlook.com Tested-by: Han Gao Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang (cherry picked from commit 579d6526aa43a155c8685a88ef8350a8c29afa47) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts index 46980e41b886ce..0cd0dc0f537c14 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts @@ -152,6 +152,18 @@ }; }; +&pcie_rc0 { + status = "okay"; +}; + +&pcie_rc1 { + status = "okay"; +}; + +&pcie_rc2 { + status = "okay"; +}; + &pinctrl { emmc_cfg: sdhci-emmc-cfg { sdhci-emmc-wp-pins { From dec247ae4caeb20d82259696ffcabdd396a3440a Mon Sep 17 00:00:00 2001 From: Zixian Zeng Date: Tue, 16 Sep 2025 21:22:50 +0800 Subject: [PATCH 22/67] UPSTREAM: riscv: dts: sophgo: Add SPI NOR node for SG2042 Add SPI NOR controller node for SG2042 Reviewed-by: Chen Wang Tested-by: Chen Wang Signed-off-by: Zixian Zeng Link: https://lore.kernel.org/r/20250916-sfg-spidts-v2-1-b5d9024fe1c8@gmail.com Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang Signed-off-by: Chen Wang (cherry picked from commit 59dc89fdfe0bbcce186116651bd017cfb9f70fc0) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi index 85d8b89cf9fc91..ec99da39150f7e 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi +++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi @@ -68,6 +68,30 @@ interrupt-parent = <&intc>; ranges; + spifmc0: spi@7000180000 { + compatible = "sophgo,sg2042-spifmc-nor"; + reg = <0x70 0x00180000 0x0 0x1000000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkgen GATE_CLK_AHB_SF>; + interrupt-parent = <&intc>; + interrupts = <108 IRQ_TYPE_LEVEL_HIGH>; + resets = <&rstgen RST_SF0>; + status = "disabled"; + }; + + spifmc1: spi@7002180000 { + compatible = "sophgo,sg2042-spifmc-nor"; + reg = <0x70 0x02180000 0x0 0x1000000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkgen GATE_CLK_AHB_SF>; + interrupt-parent = <&intc>; + interrupts = <109 IRQ_TYPE_LEVEL_HIGH>; + resets = <&rstgen RST_SF1>; + status = "disabled"; + }; + i2c0: i2c@7030005000 { compatible = "snps,designware-i2c"; reg = <0x70 0x30005000 0x0 0x1000>; From e3d861ca42c1c2945920207f7570eb51429d222c Mon Sep 17 00:00:00 2001 From: Zixian Zeng Date: Tue, 16 Sep 2025 21:22:51 +0800 Subject: [PATCH 23/67] UPSTREAM: riscv: dts: sophgo: Enable SPI NOR node for PioneerBox Enable SPI NOR node for PioneerBox device tree According to PioneerBox schematic, SPI-NOR Flash cannot support QSPI due to hardware design. Thus spi-(tx|rx)-bus-width must be set to 1. Reviewed-by: Chen Wang Tested-by: Chen Wang Signed-off-by: Zixian Zeng Link: https://lore.kernel.org/r/20250916-sfg-spidts-v2-2-b5d9024fe1c8@gmail.com Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang Signed-off-by: Chen Wang (cherry picked from commit f49314cbbc98f9ab2bf4eb82ccacbf79f179db6c) Signed-off-by: Han Gao --- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts index c4d5f8d7d4ad3f..54d8386bf9c0ff 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts @@ -150,6 +150,30 @@ status = "okay"; }; +&spifmc0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +}; + +&spifmc1 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +}; + &uart0 { pinctrl-0 = <&uart0_cfg>; pinctrl-names = "default"; From 21c359e857ad0aa3c040ecc2d27bf0d218358ce5 Mon Sep 17 00:00:00 2001 From: Zixian Zeng Date: Tue, 16 Sep 2025 21:22:52 +0800 Subject: [PATCH 24/67] UPSTREAM: riscv: dts: sophgo: Enable SPI NOR node for SG2042_EVB_V1 Enable SPI NOR node for SG2042_EVB_V1 device tree According to SG2042_EVB_V1 schematic, SPI-NOR Flash cannot support QSPI due to hardware design. Thus spi-(tx|rx)-bus-width must be set to 1. Signed-off-by: Han Gao Signed-off-by: Zixian Zeng Link: https://lore.kernel.org/r/20250916-sfg-spidts-v2-3-b5d9024fe1c8@gmail.com Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang Signed-off-by: Chen Wang (cherry picked from commit 11f4d84c9f724ec4c6810567d6b9713b054bb28b) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts index a186d036cf3606..b116dfa904cd98 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v1.dts @@ -250,6 +250,30 @@ status = "okay"; }; +&spifmc0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +}; + +&spifmc1 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +}; + &uart0 { pinctrl-0 = <&uart0_cfg>; pinctrl-names = "default"; From 1c4b31ad89ae9f73106d2c1278841678c2c65a63 Mon Sep 17 00:00:00 2001 From: Zixian Zeng Date: Tue, 16 Sep 2025 21:22:53 +0800 Subject: [PATCH 25/67] UPSTREAM: riscv: dts: sophgo: Enable SPI NOR node for SG2042_EVB_V2 Enable SPI NOR node for SG2042_EVB_V2 device tree According to SG2042_EVB_V2 schematic, SPI-NOR Flash cannot support QSPI due to hardware design. Thus spi-(tx|rx)-bus-width must be set to 1. Signed-off-by: Han Gao Signed-off-by: Zixian Zeng Link: https://lore.kernel.org/r/20250916-sfg-spidts-v2-4-b5d9024fe1c8@gmail.com Signed-off-by: Inochi Amaoto Signed-off-by: Chen Wang Signed-off-by: Chen Wang (cherry picked from commit af5eb17ff893bf6e52680a31059e1816749c2d20) Signed-off-by: Han Gao --- arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts index 0cd0dc0f537c14..b2ceae2d8829ec 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-evb-v2.dts @@ -238,6 +238,18 @@ status = "okay"; }; +&spifmc1 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +}; + &uart0 { pinctrl-0 = <&uart0_cfg>; pinctrl-names = "default"; From b128920822ae547735e7845f7dcc1fbe42c4cc10 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Fri, 14 Nov 2025 08:38:03 +0800 Subject: [PATCH 26/67] UPSTREAM: dt-bindings: net: sophgo,sg2044-dwmac: add phy mode restriction As the ethernet controller of SG2044 and SG2042 only supports RGMII phy. Add phy-mode property to restrict the value. Also, since SG2042 has internal rx delay in its mac, make only "rgmii-txid" and "rgmii-id" valid for phy-mode. Fixes: e281c48a7336 ("dt-bindings: net: sophgo,sg2044-dwmac: Add support for Sophgo SG2042 dwmac") Signed-off-by: Inochi Amaoto Acked-by: Conor Dooley Link: https://patch.msgid.link/20251114003805.494387-2-inochiama@gmail.com Signed-off-by: Jakub Kicinski (cherry picked from commit 6b1aa3c87fcbf06b29b1a7123c386ad5cf2c8e9b) Signed-off-by: Han Gao --- .../bindings/net/sophgo,sg2044-dwmac.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/net/sophgo,sg2044-dwmac.yaml b/Documentation/devicetree/bindings/net/sophgo,sg2044-dwmac.yaml index ce21979a2d9a43..e8d3814db0e94f 100644 --- a/Documentation/devicetree/bindings/net/sophgo,sg2044-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/sophgo,sg2044-dwmac.yaml @@ -70,6 +70,25 @@ required: allOf: - $ref: snps,dwmac.yaml# + - if: + properties: + compatible: + contains: + const: sophgo,sg2042-dwmac + then: + properties: + phy-mode: + enum: + - rgmii-rxid + - rgmii-id + else: + properties: + phy-mode: + enum: + - rgmii + - rgmii-rxid + - rgmii-txid + - rgmii-id unevaluatedProperties: false From a8d1f9544020359f917ca314d46418ad19a4334b Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Fri, 14 Nov 2025 08:38:04 +0800 Subject: [PATCH 27/67] UPSTREAM: net: phy: Add helper for fixing RGMII PHY mode based on internal mac delay The "phy-mode" property of devicetree indicates whether the PCB has delay now, which means the mac needs to modify the PHY mode based on whether there is an internal delay in the mac. This modification is similar for many ethernet drivers. To simplify code, define the helper phy_fix_phy_mode_for_mac_delays(speed, mac_txid, mac_rxid) to fix PHY mode based on whether mac adds internal delay. Suggested-by: Russell King (Oracle) Signed-off-by: Inochi Amaoto Reviewed-by: Maxime Chevallier Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251114003805.494387-3-inochiama@gmail.com Signed-off-by: Jakub Kicinski (cherry picked from commit 24afd7827efb7c69adfc41835390470e3eec4740) Signed-off-by: Han Gao --- drivers/net/phy/phy-core.c | 43 ++++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 3 +++ 2 files changed, 46 insertions(+) diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 605ca20ae192d7..0c63e6ba2cb0cd 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -101,6 +101,49 @@ const char *phy_rate_matching_to_str(int rate_matching) } EXPORT_SYMBOL_GPL(phy_rate_matching_to_str); +/** + * phy_fix_phy_mode_for_mac_delays - Convenience function for fixing PHY + * mode based on whether mac adds internal delay + * + * @interface: The current interface mode of the port + * @mac_txid: True if the mac adds internal tx delay + * @mac_rxid: True if the mac adds internal rx delay + * + * Return: fixed PHY mode, or PHY_INTERFACE_MODE_NA if the interface can + * not apply the internal delay + */ +phy_interface_t phy_fix_phy_mode_for_mac_delays(phy_interface_t interface, + bool mac_txid, bool mac_rxid) +{ + if (!phy_interface_mode_is_rgmii(interface)) + return interface; + + if (mac_txid && mac_rxid) { + if (interface == PHY_INTERFACE_MODE_RGMII_ID) + return PHY_INTERFACE_MODE_RGMII; + return PHY_INTERFACE_MODE_NA; + } + + if (mac_txid) { + if (interface == PHY_INTERFACE_MODE_RGMII_ID) + return PHY_INTERFACE_MODE_RGMII_RXID; + if (interface == PHY_INTERFACE_MODE_RGMII_TXID) + return PHY_INTERFACE_MODE_RGMII; + return PHY_INTERFACE_MODE_NA; + } + + if (mac_rxid) { + if (interface == PHY_INTERFACE_MODE_RGMII_ID) + return PHY_INTERFACE_MODE_RGMII_TXID; + if (interface == PHY_INTERFACE_MODE_RGMII_RXID) + return PHY_INTERFACE_MODE_RGMII; + return PHY_INTERFACE_MODE_NA; + } + + return interface; +} +EXPORT_SYMBOL_GPL(phy_fix_phy_mode_for_mac_delays); + /** * phy_interface_num_ports - Return the number of links that can be carried by * a given MAC-PHY physical link. Returns 0 if this is diff --git a/include/linux/phy.h b/include/linux/phy.h index 3c7634482356e2..0bc00a4cceb241 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1813,6 +1813,9 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev) return phydev->is_pseudo_fixed_link; } +phy_interface_t phy_fix_phy_mode_for_mac_delays(phy_interface_t interface, + bool mac_txid, bool mac_rxid); + int phy_save_page(struct phy_device *phydev); int phy_select_page(struct phy_device *phydev, int page); int phy_restore_page(struct phy_device *phydev, int oldpage, int ret); From 19d2a3ed81a3d3c7e6e5748676d1f7b352326cad Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Fri, 14 Nov 2025 08:38:05 +0800 Subject: [PATCH 28/67] UPSTREAM: net: stmmac: dwmac-sophgo: Add phy interface filter As the SG2042 has an internal rx delay, the delay should be removed when initializing the mac, otherwise the phy will be misconfigurated. Fixes: 543009e2d4cd ("net: stmmac: dwmac-sophgo: Add support for Sophgo SG2042 SoC") Signed-off-by: Inochi Amaoto Tested-by: Han Gao Reviewed-by: Andrew Lunn Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251114003805.494387-4-inochiama@gmail.com Signed-off-by: Jakub Kicinski (cherry picked from commit db37c6e510deabc9b0ee27c08f1c5aaa19f2e8ef) Signed-off-by: Han Gao --- .../ethernet/stmicro/stmmac/dwmac-sophgo.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c index 24ce17ea35c4ff..44d4ceb8415f60 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c @@ -7,11 +7,16 @@ #include #include +#include #include #include #include "stmmac_platform.h" +struct sophgo_dwmac_data { + bool has_internal_rx_delay; +}; + static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat, struct stmmac_resources *stmmac_res) @@ -31,6 +36,7 @@ static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, static int sophgo_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; + const struct sophgo_dwmac_data *data; struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; int ret; @@ -49,11 +55,23 @@ static int sophgo_dwmac_probe(struct platform_device *pdev) if (ret) return ret; + data = device_get_match_data(&pdev->dev); + if (data && data->has_internal_rx_delay) { + plat_dat->phy_interface = phy_fix_phy_mode_for_mac_delays(plat_dat->phy_interface, + false, true); + if (plat_dat->phy_interface == PHY_INTERFACE_MODE_NA) + return -EINVAL; + } + return stmmac_dvr_probe(dev, plat_dat, &stmmac_res); } +static const struct sophgo_dwmac_data sg2042_dwmac_data = { + .has_internal_rx_delay = true, +}; + static const struct of_device_id sophgo_dwmac_match[] = { - { .compatible = "sophgo,sg2042-dwmac" }, + { .compatible = "sophgo,sg2042-dwmac", .data = &sg2042_dwmac_data }, { .compatible = "sophgo,sg2044-dwmac" }, { /* sentinel */ } }; From 24c3eb022784c412984e88b11d6a21eb86f55453 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:43:54 +0800 Subject: [PATCH 29/67] Revert "FROMLIST: perf vendor events riscv: add T-HEAD C920V2 JSON support" This reverts commit 472d9c022817f36b704748852bafc4113496b07c. --- tools/perf/pmu-events/arch/riscv/mapfile.csv | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/riscv/mapfile.csv b/tools/perf/pmu-events/arch/riscv/mapfile.csv index d5eea7f9aa9a41..0a7e7dcc81be49 100644 --- a/tools/perf/pmu-events/arch/riscv/mapfile.csv +++ b/tools/perf/pmu-events/arch/riscv/mapfile.csv @@ -20,6 +20,5 @@ 0x489-0x8000000000000008-0x[[:xdigit:]]+,v1,sifive/p550,core 0x489-0x8000000000000[1-6]08-0x[9b][[:xdigit:]]+,v1,sifive/p650,core 0x5b7-0x0-0x0,v1,thead/c900-legacy,core -0x5b7-0x80000000090c0d00-0x2047000,v1,thead/c900-legacy,core 0x67e-0x80000000db0000[89]0-0x[[:xdigit:]]+,v1,starfive/dubhe-80,core 0x31e-0x8000000000008a45-0x[[:xdigit:]]+,v1,andes/ax45,core From acd959de5f1a47014779e3b3ef272fa616bddd7b Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 14 Oct 2025 09:48:29 +0800 Subject: [PATCH 30/67] UPSTREAM: perf vendor events riscv: add T-HEAD C920V2 JSON support T-HEAD C920 has a V2 iteration, which supports Sscompmf. The V2 iteration supports the same perf events as V1. Reuse T-HEAD c900-legacy JSON file for T-HEAD C920V2. Signed-off-by: Inochi Amaoto Acked-by: Paul Walmsley Signed-off-by: Namhyung Kim (cherry picked from commit c9573287729bc5ed3d2adbc028fe33d265917ae5) Signed-off-by: Han Gao --- tools/perf/pmu-events/arch/riscv/mapfile.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/pmu-events/arch/riscv/mapfile.csv b/tools/perf/pmu-events/arch/riscv/mapfile.csv index 0a7e7dcc81be49..d5eea7f9aa9a41 100644 --- a/tools/perf/pmu-events/arch/riscv/mapfile.csv +++ b/tools/perf/pmu-events/arch/riscv/mapfile.csv @@ -20,5 +20,6 @@ 0x489-0x8000000000000008-0x[[:xdigit:]]+,v1,sifive/p550,core 0x489-0x8000000000000[1-6]08-0x[9b][[:xdigit:]]+,v1,sifive/p650,core 0x5b7-0x0-0x0,v1,thead/c900-legacy,core +0x5b7-0x80000000090c0d00-0x2047000,v1,thead/c900-legacy,core 0x67e-0x80000000db0000[89]0-0x[[:xdigit:]]+,v1,starfive/dubhe-80,core 0x31e-0x8000000000008a45-0x[[:xdigit:]]+,v1,andes/ax45,core From dd5c40a96f47b90a5719ac3894a329bdb9166359 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:45:11 +0800 Subject: [PATCH 31/67] Revert "FROMLIST: dt-bindings: pwm: Add T-HEAD PWM controller" This reverts commit 7175a4011648197576e48695cf5e042346190348. --- .../bindings/pwm/thead,th1520-pwm.yaml | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml deleted file mode 100644 index e75d8e9f24c50b..00000000000000 --- a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: T-HEAD TH1520 PWM - -maintainers: - - Jisheng Zhang - -allOf: - - $ref: pwm.yaml# - -properties: - compatible: - enum: - - thead,th1520-pwm - - reg: - maxItems: 1 - - clocks: - maxItems: 1 - - "#pwm-cells": - const: 3 - -required: - - compatible - - reg - - clocks - -additionalProperties: false - -examples: - - | - - pwm@ec01c000 { - compatible = "thead,th1520-pwm"; - reg = <0xec01c000 0x1000>; - clocks = <&clk 1>; - #pwm-cells = <3>; - }; From f760509ae4c4767f01670e80400c174fc25c3cc3 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:45:49 +0800 Subject: [PATCH 32/67] Revert "XUANTIE: drivers: pwm: fix pwm enable status check error" This reverts commit 84b2a0687915222f87208052e8e4f1990d9c29bb. --- drivers/pwm/pwm-thead.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c index 01db22918e3954..31590f91aad7c5 100644 --- a/drivers/pwm/pwm-thead.c +++ b/drivers/pwm/pwm-thead.c @@ -51,7 +51,6 @@ #define THEAD_PWM_FP(n) (THEAD_PWM_CHN_BASE(n) + 0x0c) #define THEAD_PWM_STATUS(n) (THEAD_PWM_CHN_BASE(n) + 0x10) #define THEAD_PWM_STATUS_CYCLE GENMASK(7, 0) -#define THEAD_PWM_STATUS_BUSY BIT(8) struct thead_pwm_chip { void __iomem *mmio_base; @@ -166,8 +165,8 @@ static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, */ state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); - val = readl(priv->mmio_base + THEAD_PWM_STATUS(pwm->hwpwm)); - state->enabled = !!(val & THEAD_PWM_STATUS_BUSY); + val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); + state->enabled = !!val; /* * val 32 bits, multiply NSEC_PER_SEC, won't overflow. */ From db28cb57d44e112cca718bfafdbf3139e3892742 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:45:54 +0800 Subject: [PATCH 33/67] Revert "BACKPORT: FROMLIST: pwm: add T-HEAD PWM driver" This reverts commit 1aaaa8c7b84b973d6c8dff6350b9343084edf96f. --- drivers/pwm/Kconfig | 11 -- drivers/pwm/Makefile | 1 - drivers/pwm/pwm-thead.c | 271 ---------------------------------------- 3 files changed, 283 deletions(-) delete mode 100644 drivers/pwm/pwm-thead.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index fac181117e4c56..c2fd3f4b62d9ea 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -748,17 +748,6 @@ config PWM_TEGRA To compile this driver as a module, choose M here: the module will be called pwm-tegra. -config PWM_THEAD - tristate "T-HEAD PWM support" - depends on ARCH_THEAD || COMPILE_TEST - depends on HAS_IOMEM - help - Generic PWM framework driver for the PWFM controller found on THEAD - SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-thead. - config PWM_TIECAP tristate "ECAP PWM support" depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c840f8bc909d6c..dfa8b4966ee19a 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -68,7 +68,6 @@ obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o -obj-$(CONFIG_PWM_THEAD) += pwm-thead.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c deleted file mode 100644 index 31590f91aad7c5..00000000000000 --- a/drivers/pwm/pwm-thead.c +++ /dev/null @@ -1,271 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * T-HEAD PWM driver - * - * Copyright (C) 2021 Alibaba Group Holding Limited. - * Copyright (C) 2023 Jisheng Zhang - * - * Limitations: - * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used - * to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle - * is used to "disable" the channel. - * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is - * started. - * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty. - * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1 - * step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it - * to 0 beforehand. - * - Polarity can only be changed if never started before. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define THEAD_PWM_MAX_NUM 6 -#define THEAD_PWM_MAX_PERIOD GENMASK(31, 0) -#define THEAD_PWM_MAX_DUTY GENMASK(31, 0) - -#define THEAD_PWM_CHN_BASE(n) ((n) * 0x20) -#define THEAD_PWM_CTRL(n) (THEAD_PWM_CHN_BASE(n) + 0x00) -#define THEAD_PWM_CTRL_START BIT(0) -#define THEAD_PWM_CTRL_SOFT_RST BIT(1) -#define THEAD_PWM_CTRL_CFG_UPDATE BIT(2) -#define THEAD_PWM_CTRL_INTEN BIT(3) -#define THEAD_PWM_CTRL_MODE GENMASK(5, 4) -#define THEAD_PWM_CTRL_MODE_CONTINUOUS FIELD_PREP(THEAD_PWM_CTRL_MODE, 2) -#define THEAD_PWM_CTRL_EVTRIG GENMASK(7, 6) -#define THEAD_PWM_CTRL_FPOUT BIT(8) -#define THEAD_PWM_CTRL_INFACTOUT BIT(9) -#define THEAD_PWM_RPT(n) (THEAD_PWM_CHN_BASE(n) + 0x04) -#define THEAD_PWM_PER(n) (THEAD_PWM_CHN_BASE(n) + 0x08) -#define THEAD_PWM_FP(n) (THEAD_PWM_CHN_BASE(n) + 0x0c) -#define THEAD_PWM_STATUS(n) (THEAD_PWM_CHN_BASE(n) + 0x10) -#define THEAD_PWM_STATUS_CYCLE GENMASK(7, 0) - -struct thead_pwm_chip { - void __iomem *mmio_base; - struct clk *clk; - u8 channel_ever_started; -}; - -static inline struct thead_pwm_chip *thead_pwm_from_chip(struct pwm_chip *chip) -{ - return pwmchip_get_drvdata(chip); -} - -static int thead_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) -{ - struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); - u32 val = THEAD_PWM_CTRL_INFACTOUT | THEAD_PWM_CTRL_FPOUT | THEAD_PWM_CTRL_MODE_CONTINUOUS; - u64 period_cycle, duty_cycle, rate; - int ret; - - /* if ever started, can't change the polarity */ - if ((priv->channel_ever_started & (1 << pwm->hwpwm)) && - state->polarity != pwm->state.polarity) - return -EINVAL; - - if (!state->enabled) { - if (pwm->state.enabled) { - val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - val &= ~THEAD_PWM_CTRL_CFG_UPDATE; - writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - - writel(0, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); - - val |= THEAD_PWM_CTRL_CFG_UPDATE; - writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - pm_runtime_put_sync(&chip->dev); - } - return 0; - } - - if (!pwm->state.enabled) { - ret = pm_runtime_resume_and_get(pwmchip_parent(chip)); - if (ret < 0) - return ret; - } - - if (state->polarity == PWM_POLARITY_INVERSED) - val &= ~THEAD_PWM_CTRL_FPOUT; - - writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - - rate = clk_get_rate(priv->clk); - /* - * The following calculations might overflow if clk is bigger - * than 1 GHz. In practise it's 24MHz, so this limitation - * is only theoretic. - */ - if (rate > NSEC_PER_SEC) - return -EINVAL; - - period_cycle = mul_u64_u64_div_u64(rate, state->period, NSEC_PER_SEC); - if (period_cycle > THEAD_PWM_MAX_PERIOD) - period_cycle = THEAD_PWM_MAX_PERIOD; - /* - * With limitation above we have period_cycle <= THEAD_PWM_MAX_PERIOD, - * so this cannot overflow. - */ - writel(period_cycle, priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); - - duty_cycle = mul_u64_u64_div_u64(rate, state->duty_cycle, NSEC_PER_SEC); - if (duty_cycle > THEAD_PWM_MAX_DUTY) - duty_cycle = THEAD_PWM_MAX_DUTY; - /* - * With limitation above we have duty_cycle <= THEAD_PWM_MAX_DUTY, - * so this cannot overflow. - */ - writel(duty_cycle, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); - - val |= THEAD_PWM_CTRL_CFG_UPDATE; - writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - - if (!pwm->state.enabled) { - val |= THEAD_PWM_CTRL_START; - writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - priv->channel_ever_started |= 1 << pwm->hwpwm; - } - - return 0; -} - -static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) -{ - struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); - u64 rate = clk_get_rate(priv->clk); - u32 val; - int ret; - - ret = pm_runtime_resume_and_get(pwmchip_parent(chip)); - if (ret < 0) - return ret; - - val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); - if (val & THEAD_PWM_CTRL_FPOUT) - state->polarity = PWM_POLARITY_NORMAL; - else - state->polarity = PWM_POLARITY_INVERSED; - - val = readl(priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); - /* - * val 32 bits, multiply NSEC_PER_SEC, won't overflow. - */ - state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); - - val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); - state->enabled = !!val; - /* - * val 32 bits, multiply NSEC_PER_SEC, won't overflow. - */ - state->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); - - pm_runtime_put_sync(&chip->dev); - - return 0; -} - -static const struct pwm_ops thead_pwm_ops = { - .apply = thead_pwm_apply, - .get_state = thead_pwm_get_state, -}; - -static int __maybe_unused thead_pwm_runtime_suspend(struct device *dev) -{ - struct thead_pwm_chip *priv = dev_get_drvdata(dev); - - clk_disable_unprepare(priv->clk); - - return 0; -} - -static int __maybe_unused thead_pwm_runtime_resume(struct device *dev) -{ - struct thead_pwm_chip *priv = dev_get_drvdata(dev); - int ret; - - ret = clk_prepare_enable(priv->clk); - if (ret) - dev_err(dev, "failed to enable pwm clock(%pe)\n", ERR_PTR(ret)); - - return ret; -} - -static int thead_pwm_probe(struct platform_device *pdev) -{ - struct thead_pwm_chip *priv; - struct pwm_chip *chip; - int ret, i; - u32 val; - - ret = devm_pm_runtime_enable(&pdev->dev); - if (ret) - return ret; - - chip = devm_pwmchip_alloc(&pdev->dev, THEAD_PWM_MAX_NUM, sizeof(*priv)); - if (IS_ERR(chip)) - return PTR_ERR(chip); - priv = thead_pwm_from_chip(chip); - - platform_set_drvdata(pdev, priv); - - priv->mmio_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->mmio_base)) - return PTR_ERR(priv->mmio_base); - - priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - chip->ops = &thead_pwm_ops; - - /* check whether PWM is ever started or not */ - for (i = 0; i < chip->npwm; i++) { - val = readl(priv->mmio_base + THEAD_PWM_FP(i)); - if (val) - priv->channel_ever_started |= 1 << i; - } - - ret = devm_pwmchip_add(&pdev->dev, chip); - if (ret) - return ret; - - return 0; -} - -static const struct of_device_id thead_pwm_dt_ids[] = { - {.compatible = "thead,th1520-pwm",}, - {/* sentinel */} -}; -MODULE_DEVICE_TABLE(of, thead_pwm_dt_ids); - -static const struct dev_pm_ops thead_pwm_pm_ops = { - SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL) -}; - -static struct platform_driver thead_pwm_driver = { - .driver = { - .name = "thead-pwm", - .of_match_table = thead_pwm_dt_ids, - .pm = &thead_pwm_pm_ops, - }, - .probe = thead_pwm_probe, -}; -module_platform_driver(thead_pwm_driver); - -MODULE_AUTHOR("Wei Liu "); -MODULE_AUTHOR("Jisheng Zhang "); -MODULE_DESCRIPTION("T-HEAD pwm driver"); -MODULE_LICENSE("GPL v2"); From d0610f08ac80042d0ca2be23075baab73e5ecd85 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Tue, 28 Oct 2025 13:22:32 +0100 Subject: [PATCH 34/67] UPSTREAM: rust: macros: Add support for 'imports_ns' to module! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kernel modules that use C symbols exported via `EXPORT_SYMBOL_NS` must declare this dependency for `modpost` verification. C modules achieve this by using the `MODULE_IMPORT_NS(NAMESPACE)` macro, which embeds an `import_ns=` tag into the `.modinfo` section. The Rust `module!` macro lacked the ability to generate these tags, resulting in build warnings for Rust drivers (like the PWM driver) that call namespaced C functions. Modify the `module!` macro's internal parser (`ModuleInfo`) to accept a new optional field `imports_ns`, which takes an array of namespace strings. Update the code generator (`ModInfoBuilder::emit`) loop to iterate over these strings and emit the corresponding `import_ns=` tags into the `.modinfo` section using the existing `#[link_section]` mechanism. This provides the necessary infrastructure for Rust modules to correctly declare their C namespace dependencies. Signed-off-by: Michal Wilczynski Acked-by: Miguel Ojeda Reviewed-by: Alice Ryhl Reviewed-by: Elle Rhumsaa Acked-by: Daniel Gomez Link: https://patch.msgid.link/20251028-pwm_fixes-v1-1-25a532d31998@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit 739ad9be61e5f53dbd8d7d7e80723d0799ff077c) Signed-off-by: Han Gao --- rust/macros/module.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust/macros/module.rs b/rust/macros/module.rs index 5ee54a00c0b656..408cd115487514 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -98,6 +98,7 @@ struct ModuleInfo { description: Option, alias: Option>, firmware: Option>, + imports_ns: Option>, } impl ModuleInfo { @@ -112,6 +113,7 @@ impl ModuleInfo { "license", "alias", "firmware", + "imports_ns", ]; const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; let mut seen_keys = Vec::new(); @@ -137,6 +139,7 @@ impl ModuleInfo { "license" => info.license = expect_string_ascii(it), "alias" => info.alias = Some(expect_string_array(it)), "firmware" => info.firmware = Some(expect_string_array(it)), + "imports_ns" => info.imports_ns = Some(expect_string_array(it)), _ => panic!("Unknown key \"{key}\". Valid keys are: {EXPECTED_KEYS:?}."), } @@ -195,6 +198,11 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { modinfo.emit("firmware", &fw); } } + if let Some(imports) = info.imports_ns { + for ns in imports { + modinfo.emit("import_ns", &ns); + } + } // Built-in modules also export the `file` modinfo string. let file = From acbf2a021dae433ae76c904d6507a6cf6ccd76ab Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:01 +0200 Subject: [PATCH 35/67] UPSTREAM: pwm: Export `pwmchip_release` for external use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upcoming Rust abstraction layer for the PWM subsystem uses a custom `dev->release` handler to safely manage the lifetime of its driver data. To prevent leaking the memory of the `struct pwm_chip` (allocated by `pwmchip_alloc`), this custom handler must also call the original `pwmchip_release` function to complete the cleanup. Make `pwmchip_release` a global, exported function so that it can be called from the Rust FFI bridge. This involves removing the `static` keyword, adding a prototype to the public header, and exporting the symbol. Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-1-a5df2405d2bd@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit ce284f882022ebcb953984c7eccf4fc4eb531978) Signed-off-by: Han Gao --- drivers/pwm/core.c | 3 ++- include/linux/pwm.h | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index ea2ccf42e81441..47c9333baaf6c7 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -1608,12 +1608,13 @@ void pwmchip_put(struct pwm_chip *chip) } EXPORT_SYMBOL_GPL(pwmchip_put); -static void pwmchip_release(struct device *pwmchip_dev) +void pwmchip_release(struct device *pwmchip_dev) { struct pwm_chip *chip = pwmchip_from_dev(pwmchip_dev); kfree(chip); } +EXPORT_SYMBOL_GPL(pwmchip_release); struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv) { diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 549ac4aaad59ba..148f056f336bbe 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -488,6 +488,12 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner); #define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE) void pwmchip_remove(struct pwm_chip *chip); +/* + * For FFI wrapper use only: + * The Rust PWM abstraction needs this to properly free the pwm_chip. + */ +void pwmchip_release(struct device *dev); + int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner); #define devm_pwmchip_add(dev, chip) __devm_pwmchip_add(dev, chip, THIS_MODULE) From 1fd3dfdef49dc7c2d82b63e26ef76893d41a5afe Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:02 +0200 Subject: [PATCH 36/67] UPSTREAM: rust: pwm: Add Kconfig and basic data structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the foundational support for PWM abstractions in Rust. This commit adds the `RUST_PWM_ABSTRACTIONS` Kconfig option to enable the feature, along with the necessary build-system support and C helpers. It also introduces the first set of safe wrappers for the PWM subsystem, covering the basic data carrying C structs and enums: - `Polarity`: A safe wrapper for `enum pwm_polarity`. - `Waveform`: A wrapper for `struct pwm_waveform`. - `State`: A wrapper for `struct pwm_state`. These types provide memory safe, idiomatic Rust representations of the core PWM data structures and form the building blocks for the abstractions that will follow. Tested-by: Drew Fustini Reviewed-by: Daniel Almeida Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-2-a5df2405d2bd@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit 7b3dce814a15bc5d9fb6124cd945291012c4ebb9) Signed-off-by: Han Gao --- MAINTAINERS | 8 +++ drivers/pwm/Kconfig | 12 ++++ rust/bindings/bindings_helper.h | 1 + rust/helpers/helpers.c | 1 + rust/helpers/pwm.c | 20 +++++++ rust/kernel/lib.rs | 2 + rust/kernel/pwm.rs | 102 ++++++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+) create mode 100644 rust/helpers/pwm.c create mode 100644 rust/kernel/pwm.rs diff --git a/MAINTAINERS b/MAINTAINERS index 695819b80abdee..d3642ea24db508 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20832,6 +20832,14 @@ F: include/linux/pwm.h F: include/linux/pwm_backlight.h K: pwm_(config|apply_might_sleep|apply_atomic|ops) +PWM SUBSYSTEM BINDINGS [RUST] +M: Michal Wilczynski +L: linux-pwm@vger.kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/helpers/pwm.c +F: rust/kernel/pwm.rs + PXA GPIO DRIVER M: Robert Jarzmik L: linux-gpio@vger.kernel.org diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index c2fd3f4b62d9ea..d87c4521268c18 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -819,4 +819,16 @@ config PWM_XILINX To compile this driver as a module, choose M here: the module will be called pwm-xilinx. + config RUST_PWM_ABSTRACTIONS + bool + depends on RUST + help + This option enables the safe Rust abstraction layer for the PWM + subsystem. It provides idiomatic wrappers and traits necessary for + writing PWM controller drivers in Rust. + + The abstractions handle resource management (like memory and reference + counting) and provide safe interfaces to the underlying C core, + allowing driver logic to be written in safe Rust. + endif diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 2e43c66635a2c9..70b11fc6338c4f 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 551da6c9b5064c..014f20df914822 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -43,6 +43,7 @@ #include "poll.c" #include "processor.c" #include "property.c" +#include "pwm.c" #include "rbtree.c" #include "rcu.c" #include "refcount.c" diff --git a/rust/helpers/pwm.c b/rust/helpers/pwm.c new file mode 100644 index 00000000000000..d75c588863685d --- /dev/null +++ b/rust/helpers/pwm.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2025 Samsung Electronics Co., Ltd. +// Author: Michal Wilczynski + +#include + +struct device *rust_helper_pwmchip_parent(const struct pwm_chip *chip) +{ + return pwmchip_parent(chip); +} + +void *rust_helper_pwmchip_get_drvdata(struct pwm_chip *chip) +{ + return pwmchip_get_drvdata(chip); +} + +void rust_helper_pwmchip_set_drvdata(struct pwm_chip *chip, void *data) +{ + pwmchip_set_drvdata(chip, data); +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3dd7bebe78882a..68c71d888fdb84 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -129,6 +129,8 @@ pub mod security; pub mod seq_file; pub mod sizes; mod static_assert; +#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)] +pub mod pwm; #[doc(hidden)] pub mod std_vendor; pub mod str; diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs new file mode 100644 index 00000000000000..beabf0086a2f1b --- /dev/null +++ b/rust/kernel/pwm.rs @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2025 Samsung Electronics Co., Ltd. +// Author: Michal Wilczynski + +//! PWM subsystem abstractions. +//! +//! C header: [`include/linux/pwm.h`](srctree/include/linux/pwm.h). + +use crate::{ + bindings, + prelude::*, + types::Opaque, +}; +use core::convert::TryFrom; + +/// PWM polarity. Mirrors [`enum pwm_polarity`](srctree/include/linux/pwm.h). +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Polarity { + /// Normal polarity (duty cycle defines the high period of the signal). + Normal, + + /// Inversed polarity (duty cycle defines the low period of the signal). + Inversed, +} + +impl TryFrom for Polarity { + type Error = Error; + + fn try_from(polarity: bindings::pwm_polarity) -> Result { + match polarity { + bindings::pwm_polarity_PWM_POLARITY_NORMAL => Ok(Polarity::Normal), + bindings::pwm_polarity_PWM_POLARITY_INVERSED => Ok(Polarity::Inversed), + _ => Err(EINVAL), + } + } +} + +impl From for bindings::pwm_polarity { + fn from(polarity: Polarity) -> Self { + match polarity { + Polarity::Normal => bindings::pwm_polarity_PWM_POLARITY_NORMAL, + Polarity::Inversed => bindings::pwm_polarity_PWM_POLARITY_INVERSED, + } + } +} + +/// Represents a PWM waveform configuration. +/// Mirrors struct [`struct pwm_waveform`](srctree/include/linux/pwm.h). +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct Waveform { + /// Total duration of one complete PWM cycle, in nanoseconds. + pub period_length_ns: u64, + + /// Duty-cycle active time, in nanoseconds. + /// + /// For a typical normal polarity configuration (active-high) this is the + /// high time of the signal. + pub duty_length_ns: u64, + + /// Duty-cycle start offset, in nanoseconds. + /// + /// Delay from the beginning of the period to the first active edge. + /// In most simple PWM setups this is `0`, so the duty cycle starts + /// immediately at each period’s start. + pub duty_offset_ns: u64, +} + +impl From for Waveform { + fn from(wf: bindings::pwm_waveform) -> Self { + Waveform { + period_length_ns: wf.period_length_ns, + duty_length_ns: wf.duty_length_ns, + duty_offset_ns: wf.duty_offset_ns, + } + } +} + +impl From for bindings::pwm_waveform { + fn from(wf: Waveform) -> Self { + bindings::pwm_waveform { + period_length_ns: wf.period_length_ns, + duty_length_ns: wf.duty_length_ns, + duty_offset_ns: wf.duty_offset_ns, + } + } +} + +/// Wrapper for PWM state [`struct pwm_state`](srctree/include/linux/pwm.h). +#[repr(transparent)] +pub struct State(bindings::pwm_state); + +impl State { + /// Creates a `State` wrapper by taking ownership of a C `pwm_state` value. + pub(crate) fn from_c(c_state: bindings::pwm_state) -> Self { + State(c_state) + } + + /// Returns `true` if the PWM signal is enabled. + pub fn enabled(&self) -> bool { + self.0.enabled + } +} From 1cbd790d3618a76f5f4fa5ba034edcb94f26b50c Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:03 +0200 Subject: [PATCH 37/67] UPSTREAM: rust: pwm: Add complete abstraction layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a comprehensive abstraction layer for the PWM subsystem to enable writing drivers in Rust. Because `Device`, `Chip`, and `PwmOps` all refer to each other, they form a single, indivisible unit with circular dependencies. They are introduced together in this single commit to create a complete, compilable abstraction layer. The main components are: - Data Wrappers: Safe, idiomatic wrappers for core C types like `pwm_device`, and `pwm_chip`. - PwmOps Trait: An interface that drivers can implement to provide their hardware-specific logic, mirroring the C `pwm_ops` interface. - FFI VTable and Adapter: A bridge to connect the high-level PwmOps trait to the C kernel's pwm_ops vtable. - Allocation and Lifetime Management: A high-level `Chip::new()` API to safely allocate a chip and a `Registration` guard that integrates with `devres` to manage the chip's registration with the PWM core. An `AlwaysRefCounted` implementation and a custom release handler prevent memory leaks by managing the chip's lifetime and freeing driver data correctly. Reviewed-by: Danilo Krummrich Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-3-a5df2405d2bd@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit d8046cd50879db371bbf6220477ec521692ab2f6) Signed-off-by: Han Gao --- rust/kernel/pwm.rs | 664 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 662 insertions(+), 2 deletions(-) diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs index beabf0086a2f1b..79fbb13cd47f75 100644 --- a/rust/kernel/pwm.rs +++ b/rust/kernel/pwm.rs @@ -8,10 +8,14 @@ use crate::{ bindings, + container_of, + device::{self, Bound}, + devres, + error::{self, to_result}, prelude::*, - types::Opaque, + types::{ARef, AlwaysRefCounted, Opaque}, }; -use core::convert::TryFrom; +use core::{convert::TryFrom, marker::PhantomData, ptr::NonNull}; /// PWM polarity. Mirrors [`enum pwm_polarity`](srctree/include/linux/pwm.h). #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -100,3 +104,659 @@ impl State { self.0.enabled } } + +/// Describes the outcome of a `round_waveform` operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RoundingOutcome { + /// The requested waveform was achievable exactly or by rounding values down. + ExactOrRoundedDown, + + /// The requested waveform could only be achieved by rounding up. + RoundedUp, +} + +/// Wrapper for a PWM device [`struct pwm_device`](srctree/include/linux/pwm.h). +#[repr(transparent)] +pub struct Device(Opaque); + +impl Device { + /// Creates a reference to a [`Device`] from a valid C pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the + /// returned [`Device`] reference. + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::pwm_device) -> &'a Self { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `Device` type being transparent makes the cast ok. + unsafe { &*ptr.cast::() } + } + + /// Returns a raw pointer to the underlying `pwm_device`. + fn as_raw(&self) -> *mut bindings::pwm_device { + self.0.get() + } + + /// Gets the hardware PWM index for this device within its chip. + pub fn hwpwm(&self) -> u32 { + // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime. + unsafe { (*self.as_raw()).hwpwm } + } + + /// Gets a reference to the parent `Chip` that this device belongs to. + pub fn chip(&self) -> &Chip { + // SAFETY: `self.as_raw()` provides a valid pointer. (*self.as_raw()).chip + // is assumed to be a valid pointer to `pwm_chip` managed by the kernel. + // Chip::from_raw's safety conditions must be met. + unsafe { Chip::::from_raw((*self.as_raw()).chip) } + } + + /// Gets the label for this PWM device, if any. + pub fn label(&self) -> Option<&CStr> { + // SAFETY: self.as_raw() provides a valid pointer. + let label_ptr = unsafe { (*self.as_raw()).label }; + if label_ptr.is_null() { + return None + } + + // SAFETY: label_ptr is non-null and points to a C string + // managed by the kernel, valid for the lifetime of the PWM device. + Some(unsafe { CStr::from_char_ptr(label_ptr) }) + } + + /// Gets a copy of the current state of this PWM device. + pub fn state(&self) -> State { + // SAFETY: `self.as_raw()` gives a valid pointer. `(*self.as_raw()).state` + // is a valid `pwm_state` struct. `State::from_c` copies this data. + State::from_c(unsafe { (*self.as_raw()).state }) + } + + /// Sets the PWM waveform configuration and enables the PWM signal. + pub fn set_waveform(&self, wf: &Waveform, exact: bool) -> Result { + let c_wf = bindings::pwm_waveform::from(*wf); + + // SAFETY: `self.as_raw()` provides a valid `*mut pwm_device` pointer. + // `&c_wf` is a valid pointer to a `pwm_waveform` struct. The C function + // handles all necessary internal locking. + let ret = unsafe { bindings::pwm_set_waveform_might_sleep(self.as_raw(), &c_wf, exact) }; + to_result(ret) + } + + /// Queries the hardware for the configuration it would apply for a given + /// request. + pub fn round_waveform(&self, wf: &mut Waveform) -> Result { + let mut c_wf = bindings::pwm_waveform::from(*wf); + + // SAFETY: `self.as_raw()` provides a valid `*mut pwm_device` pointer. + // `&mut c_wf` is a valid pointer to a mutable `pwm_waveform` struct that + // the C function will update. + let ret = unsafe { bindings::pwm_round_waveform_might_sleep(self.as_raw(), &mut c_wf) }; + + to_result(ret)?; + + *wf = Waveform::from(c_wf); + + if ret == 1 { + Ok(RoundingOutcome::RoundedUp) + } else { + Ok(RoundingOutcome::ExactOrRoundedDown) + } + } + + /// Reads the current waveform configuration directly from the hardware. + pub fn get_waveform(&self) -> Result { + let mut c_wf = bindings::pwm_waveform::default(); + + // SAFETY: `self.as_raw()` is a valid pointer. We provide a valid pointer + // to a stack-allocated `pwm_waveform` struct for the kernel to fill. + let ret = unsafe { bindings::pwm_get_waveform_might_sleep(self.as_raw(), &mut c_wf) }; + + to_result(ret)?; + + Ok(Waveform::from(c_wf)) + } +} + +/// The result of a `round_waveform_tohw` operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RoundedWaveform { + /// A status code, 0 for success or 1 if values were rounded up. + pub status: c_int, + /// The driver-specific hardware representation of the waveform. + pub hardware_waveform: WfHw, +} + +/// Trait defining the operations for a PWM driver. +pub trait PwmOps: 'static + Sized { + /// The driver-specific hardware representation of a waveform. + /// + /// This type must be [`Copy`], [`Default`], and fit within `PWM_WFHWSIZE`. + type WfHw: Copy + Default; + + /// Optional hook for when a PWM device is requested. + fn request( + _chip: &Chip, + _pwm: &Device, + _parent_dev: &device::Device, + ) -> Result { + Ok(()) + } + + /// Optional hook for capturing a PWM signal. + fn capture( + _chip: &Chip, + _pwm: &Device, + _result: &mut bindings::pwm_capture, + _timeout: usize, + _parent_dev: &device::Device, + ) -> Result { + Err(ENOTSUPP) + } + + /// Convert a generic waveform to the hardware-specific representation. + /// This is typically a pure calculation and does not perform I/O. + fn round_waveform_tohw( + _chip: &Chip, + _pwm: &Device, + _wf: &Waveform, + ) -> Result> { + Err(ENOTSUPP) + } + + /// Convert a hardware-specific representation back to a generic waveform. + /// This is typically a pure calculation and does not perform I/O. + fn round_waveform_fromhw( + _chip: &Chip, + _pwm: &Device, + _wfhw: &Self::WfHw, + _wf: &mut Waveform, + ) -> Result { + Err(ENOTSUPP) + } + + /// Read the current hardware configuration into the hardware-specific representation. + fn read_waveform( + _chip: &Chip, + _pwm: &Device, + _parent_dev: &device::Device, + ) -> Result { + Err(ENOTSUPP) + } + + /// Write a hardware-specific waveform configuration to the hardware. + fn write_waveform( + _chip: &Chip, + _pwm: &Device, + _wfhw: &Self::WfHw, + _parent_dev: &device::Device, + ) -> Result { + Err(ENOTSUPP) + } +} + +/// Bridges Rust `PwmOps` to the C `pwm_ops` vtable. +struct Adapter { + _p: PhantomData, +} + +impl Adapter { + const VTABLE: PwmOpsVTable = create_pwm_ops::(); + + /// # Safety + /// + /// `wfhw_ptr` must be valid for writes of `size_of::()` bytes. + unsafe fn serialize_wfhw(wfhw: &T::WfHw, wfhw_ptr: *mut c_void) -> Result { + let size = core::mem::size_of::(); + + build_assert!(size <= bindings::PWM_WFHWSIZE as usize); + + // SAFETY: The caller ensures `wfhw_ptr` is valid for `size` bytes. + unsafe { + core::ptr::copy_nonoverlapping( + core::ptr::from_ref::(wfhw).cast::(), + wfhw_ptr.cast::(), + size, + ); + } + + Ok(()) + } + + /// # Safety + /// + /// `wfhw_ptr` must be valid for reads of `size_of::()` bytes. + unsafe fn deserialize_wfhw(wfhw_ptr: *const c_void) -> Result { + let size = core::mem::size_of::(); + + build_assert!(size <= bindings::PWM_WFHWSIZE as usize); + + let mut wfhw = T::WfHw::default(); + // SAFETY: The caller ensures `wfhw_ptr` is valid for `size` bytes. + unsafe { + core::ptr::copy_nonoverlapping( + wfhw_ptr.cast::(), + core::ptr::from_mut::(&mut wfhw).cast::(), + size, + ); + } + + Ok(wfhw) + } + + /// # Safety + /// + /// `dev` must be a valid pointer to a `bindings::device` embedded within a + /// `bindings::pwm_chip`. This function is called by the device core when the + /// last reference to the device is dropped. + unsafe extern "C" fn release_callback(dev: *mut bindings::device) { + // SAFETY: The function's contract guarantees that `dev` points to a `device` + // field embedded within a valid `pwm_chip`. `container_of!` can therefore + // safely calculate the address of the containing struct. + let c_chip_ptr = unsafe { container_of!(dev, bindings::pwm_chip, dev) }; + + // SAFETY: `c_chip_ptr` is a valid pointer to a `pwm_chip` as established + // above. Calling this FFI function is safe. + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) }; + + // SAFETY: The driver data was initialized in `new`. We run its destructor here. + unsafe { core::ptr::drop_in_place(drvdata_ptr.cast::()) }; + + // Now, call the original release function to free the `pwm_chip` itself. + // SAFETY: `dev` is the valid pointer passed into this callback, which is + // the expected argument for `pwmchip_release`. + unsafe { bindings::pwmchip_release(dev); } + } + + /// # Safety + /// + /// Pointers from C must be valid. + unsafe extern "C" fn request_callback( + chip_ptr: *mut bindings::pwm_chip, + pwm_ptr: *mut bindings::pwm_device, + ) -> c_int { + // SAFETY: PWM core guarentees `chip_ptr` and `pwm_ptr` are valid pointers. + let (chip, pwm) = unsafe { (Chip::::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; + + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. + let bound_parent = unsafe { chip.bound_parent_device() }; + match T::request(chip, pwm, bound_parent) { + Ok(()) => 0, + Err(e) => e.to_errno(), + } + } + + /// # Safety + /// + /// Pointers from C must be valid. + unsafe extern "C" fn capture_callback( + chip_ptr: *mut bindings::pwm_chip, + pwm_ptr: *mut bindings::pwm_device, + res: *mut bindings::pwm_capture, + timeout: usize, + ) -> c_int { + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid + // pointers. + let (chip, pwm, result) = unsafe { + ( + Chip::::from_raw(chip_ptr), + Device::from_raw(pwm_ptr), + &mut *res, + ) + }; + + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. + let bound_parent = unsafe { chip.bound_parent_device() }; + match T::capture(chip, pwm, result, timeout, bound_parent) { + Ok(()) => 0, + Err(e) => e.to_errno(), + } + } + + /// # Safety + /// + /// Pointers from C must be valid. + unsafe extern "C" fn round_waveform_tohw_callback( + chip_ptr: *mut bindings::pwm_chip, + pwm_ptr: *mut bindings::pwm_device, + wf_ptr: *const bindings::pwm_waveform, + wfhw_ptr: *mut c_void, + ) -> c_int { + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid + // pointers. + let (chip, pwm, wf) = unsafe { + ( + Chip::::from_raw(chip_ptr), + Device::from_raw(pwm_ptr), + Waveform::from(*wf_ptr), + ) + }; + match T::round_waveform_tohw(chip, pwm, &wf) { + Ok(rounded) => { + // SAFETY: `wfhw_ptr` is valid per this function's safety contract. + if unsafe { Self::serialize_wfhw(&rounded.hardware_waveform, wfhw_ptr) }.is_err() { + return EINVAL.to_errno(); + } + rounded.status + } + Err(e) => e.to_errno(), + } + } + + /// # Safety + /// + /// Pointers from C must be valid. + unsafe extern "C" fn round_waveform_fromhw_callback( + chip_ptr: *mut bindings::pwm_chip, + pwm_ptr: *mut bindings::pwm_device, + wfhw_ptr: *const c_void, + wf_ptr: *mut bindings::pwm_waveform, + ) -> c_int { + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid + // pointers. + let (chip, pwm) = unsafe { (Chip::::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; + // SAFETY: `deserialize_wfhw`'s safety contract is met by this function's contract. + let wfhw = match unsafe { Self::deserialize_wfhw(wfhw_ptr) } { + Ok(v) => v, + Err(e) => return e.to_errno(), + }; + + let mut rust_wf = Waveform::default(); + match T::round_waveform_fromhw(chip, pwm, &wfhw, &mut rust_wf) { + Ok(()) => { + // SAFETY: `wf_ptr` is guaranteed valid by the C caller. + unsafe { + *wf_ptr = rust_wf.into(); + }; + 0 + } + Err(e) => e.to_errno(), + } + } + + /// # Safety + /// + /// Pointers from C must be valid. + unsafe extern "C" fn read_waveform_callback( + chip_ptr: *mut bindings::pwm_chip, + pwm_ptr: *mut bindings::pwm_device, + wfhw_ptr: *mut c_void, + ) -> c_int { + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid + // pointers. + let (chip, pwm) = unsafe { (Chip::::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; + + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. + let bound_parent = unsafe { chip.bound_parent_device() }; + match T::read_waveform(chip, pwm, bound_parent) { + // SAFETY: `wfhw_ptr` is valid per this function's safety contract. + Ok(wfhw) => match unsafe { Self::serialize_wfhw(&wfhw, wfhw_ptr) } { + Ok(()) => 0, + Err(e) => e.to_errno(), + }, + Err(e) => e.to_errno(), + } + } + + /// # Safety + /// + /// Pointers from C must be valid. + unsafe extern "C" fn write_waveform_callback( + chip_ptr: *mut bindings::pwm_chip, + pwm_ptr: *mut bindings::pwm_device, + wfhw_ptr: *const c_void, + ) -> c_int { + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid + // pointers. + let (chip, pwm) = unsafe { (Chip::::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; + + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. + let bound_parent = unsafe { chip.bound_parent_device() }; + + // SAFETY: `wfhw_ptr` is valid per this function's safety contract. + let wfhw = match unsafe { Self::deserialize_wfhw(wfhw_ptr) } { + Ok(v) => v, + Err(e) => return e.to_errno(), + }; + match T::write_waveform(chip, pwm, &wfhw, bound_parent) { + Ok(()) => 0, + Err(e) => e.to_errno(), + } + } +} + +/// VTable structure wrapper for PWM operations. +/// Mirrors [`struct pwm_ops`](srctree/include/linux/pwm.h). +#[repr(transparent)] +pub struct PwmOpsVTable(bindings::pwm_ops); + +// SAFETY: PwmOpsVTable is Send. The vtable contains only function pointers +// and a size, which are simple data types that can be safely moved across +// threads. The thread-safety of calling these functions is handled by the +// kernel's locking mechanisms. +unsafe impl Send for PwmOpsVTable {} + +// SAFETY: PwmOpsVTable is Sync. The vtable is immutable after it is created, +// so it can be safely referenced and accessed concurrently by multiple threads +// e.g. to read the function pointers. +unsafe impl Sync for PwmOpsVTable {} + +impl PwmOpsVTable { + /// Returns a raw pointer to the underlying `pwm_ops` struct. + pub(crate) fn as_raw(&self) -> *const bindings::pwm_ops { + &self.0 + } +} + +/// Creates a PWM operations vtable for a type `T` that implements `PwmOps`. +/// +/// This is used to bridge Rust trait implementations to the C `struct pwm_ops` +/// expected by the kernel. +pub const fn create_pwm_ops() -> PwmOpsVTable { + // SAFETY: `core::mem::zeroed()` is unsafe. For `pwm_ops`, all fields are + // `Option` or data, so a zeroed pattern (None/0) is valid initially. + let mut ops: bindings::pwm_ops = unsafe { core::mem::zeroed() }; + + ops.request = Some(Adapter::::request_callback); + ops.capture = Some(Adapter::::capture_callback); + + ops.round_waveform_tohw = Some(Adapter::::round_waveform_tohw_callback); + ops.round_waveform_fromhw = Some(Adapter::::round_waveform_fromhw_callback); + ops.read_waveform = Some(Adapter::::read_waveform_callback); + ops.write_waveform = Some(Adapter::::write_waveform_callback); + ops.sizeof_wfhw = core::mem::size_of::(); + + PwmOpsVTable(ops) +} + +/// Wrapper for a PWM chip/controller ([`struct pwm_chip`](srctree/include/linux/pwm.h)). +#[repr(transparent)] +pub struct Chip(Opaque, PhantomData); + +impl Chip { + /// Creates a reference to a [`Chip`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the + /// returned [`Chip`] reference. + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::pwm_chip) -> &'a Self { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `Chip` type being transparent makes the cast ok. + unsafe { &*ptr.cast::() } + } + + /// Returns a raw pointer to the underlying `pwm_chip`. + pub(crate) fn as_raw(&self) -> *mut bindings::pwm_chip { + self.0.get() + } + + /// Gets the number of PWM channels (hardware PWMs) on this chip. + pub fn num_channels(&self) -> u32 { + // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime. + unsafe { (*self.as_raw()).npwm } + } + + /// Returns `true` if the chip supports atomic operations for configuration. + pub fn is_atomic(&self) -> bool { + // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime. + unsafe { (*self.as_raw()).atomic } + } + + /// Returns a reference to the embedded `struct device` abstraction. + pub fn device(&self) -> &device::Device { + // SAFETY: + // - `self.as_raw()` provides a valid pointer to `bindings::pwm_chip`. + // - The `dev` field is an instance of `bindings::device` embedded + // within `pwm_chip`. + // - Taking a pointer to this embedded field is valid. + // - `device::Device` is `#[repr(transparent)]`. + // - The lifetime of the returned reference is tied to `self`. + unsafe { device::Device::from_raw(&raw mut (*self.as_raw()).dev) } + } + + /// Gets the typed driver specific data associated with this chip's embedded device. + pub fn drvdata(&self) -> &T { + // SAFETY: `pwmchip_get_drvdata` returns the pointer to the private data area, + // which we know holds our `T`. The pointer is valid for the lifetime of `self`. + unsafe { &*bindings::pwmchip_get_drvdata(self.as_raw()).cast::() } + } + + /// Returns a reference to the parent device of this PWM chip's device. + /// + /// # Safety + /// + /// The caller must guarantee that the parent device exists and is bound. + /// This is guaranteed by the PWM core during `PwmOps` callbacks. + unsafe fn bound_parent_device(&self) -> &device::Device { + // SAFETY: Per the function's safety contract, the parent device exists. + let parent = unsafe { self.device().parent().unwrap_unchecked() }; + + // SAFETY: Per the function's safety contract, the parent device is bound. + // This is guaranteed by the PWM core during `PwmOps` callbacks. + unsafe { parent.as_bound() } + } + + /// Allocates and wraps a PWM chip using `bindings::pwmchip_alloc`. + /// + /// Returns an [`ARef`] managing the chip's lifetime via refcounting + /// on its embedded `struct device`. + pub fn new( + parent_dev: &device::Device, + num_channels: u32, + data: impl pin_init::PinInit, + ) -> Result> { + let sizeof_priv = core::mem::size_of::(); + // SAFETY: `pwmchip_alloc` allocates memory for the C struct and our private data. + let c_chip_ptr_raw = unsafe { + bindings::pwmchip_alloc(parent_dev.as_raw(), num_channels, sizeof_priv) + }; + + let c_chip_ptr: *mut bindings::pwm_chip = error::from_err_ptr(c_chip_ptr_raw)?; + + // SAFETY: The `drvdata` pointer is the start of the private area, which is where + // we will construct our `T` object. + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) }; + + // SAFETY: We construct the `T` object in-place in the allocated private memory. + unsafe { data.__pinned_init(drvdata_ptr.cast())? }; + + // SAFETY: `c_chip_ptr` points to a valid chip. + unsafe { (*c_chip_ptr).dev.release = Some(Adapter::::release_callback); } + + // SAFETY: `c_chip_ptr` points to a valid chip. + // The `Adapter`'s `VTABLE` has a 'static lifetime, so the pointer + // returned by `as_raw()` is always valid. + unsafe { (*c_chip_ptr).ops = Adapter::::VTABLE.as_raw(); } + + // Cast the `*mut bindings::pwm_chip` to `*mut Chip`. This is valid because + // `Chip` is `repr(transparent)` over `Opaque`, and + // `Opaque` is `repr(transparent)` over `T`. + let chip_ptr_as_self = c_chip_ptr.cast::(); + + // SAFETY: `chip_ptr_as_self` points to a valid `Chip` (layout-compatible with + // `bindings::pwm_chip`) whose embedded device has refcount 1. + // `ARef::from_raw` takes this pointer and manages it via `AlwaysRefCounted`. + Ok(unsafe { ARef::from_raw(NonNull::new_unchecked(chip_ptr_as_self)) }) + } +} + +// SAFETY: Implements refcounting for `Chip` using the embedded `struct device`. +unsafe impl AlwaysRefCounted for Chip { + #[inline] + fn inc_ref(&self) { + // SAFETY: `self.0.get()` points to a valid `pwm_chip` because `self` exists. + // The embedded `dev` is valid. `get_device` increments its refcount. + unsafe { bindings::get_device(&raw mut (*self.0.get()).dev); } + } + + #[inline] + unsafe fn dec_ref(obj: NonNull>) { + let c_chip_ptr = obj.cast::().as_ptr(); + + // SAFETY: `obj` is a valid pointer to a `Chip` (and thus `bindings::pwm_chip`) + // with a non-zero refcount. `put_device` handles decrement and final release. + unsafe { bindings::put_device(&raw mut (*c_chip_ptr).dev); } + } +} + +// SAFETY: `Chip` is a wrapper around `*mut bindings::pwm_chip`. The underlying C +// structure's state is managed and synchronized by the kernel's device model +// and PWM core locking mechanisms. Therefore, it is safe to move the `Chip` +// wrapper (and the pointer it contains) across threads. +unsafe impl Send for Chip {} + +// SAFETY: It is safe for multiple threads to have shared access (`&Chip`) because +// the `Chip` data is immutable from the Rust side without holding the appropriate +// kernel locks, which the C core is responsible for. Any interior mutability is +// handled and synchronized by the C kernel code. +unsafe impl Sync for Chip {} + +/// A resource guard that ensures `pwmchip_remove` is called on drop. +/// +/// This struct is intended to be managed by the `devres` framework by transferring its ownership +/// via [`Devres::register`]. This ties the lifetime of the PWM chip registration +/// to the lifetime of the underlying device. +pub struct Registration { + chip: ARef>, +} + +impl Registration { + /// Registers a PWM chip with the PWM subsystem. + /// + /// Transfers its ownership to the `devres` framework, which ties its lifetime + /// to the parent device. + /// On unbind of the parent device, the `devres` entry will be dropped, automatically + /// calling `pwmchip_remove`. This function should be called from the driver's `probe`. + pub fn register( + dev: &device::Device, + chip: ARef>, + ) -> Result { + let chip_parent = chip.device().parent().ok_or(EINVAL)?; + if dev.as_raw() != chip_parent.as_raw() { + return Err(EINVAL); + } + + let c_chip_ptr = chip.as_raw(); + + // SAFETY: `c_chip_ptr` points to a valid chip with its ops initialized. + // `__pwmchip_add` is the C function to register the chip with the PWM core. + unsafe { + to_result(bindings::__pwmchip_add(c_chip_ptr, core::ptr::null_mut()))?; + } + + let registration = Registration { chip }; + + devres::register(dev, registration, GFP_KERNEL) + } +} + +impl Drop for Registration { + fn drop(&mut self) { + let chip_raw = self.chip.as_raw(); + + // SAFETY: `chip_raw` points to a chip that was successfully registered. + // `bindings::pwmchip_remove` is the correct C function to unregister it. + // This `drop` implementation is called automatically by `devres` on driver unbind. + unsafe { bindings::pwmchip_remove(chip_raw); } + } +} From d8f160213ccf5f39a318d9adb0167ebdfaf31052 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Tue, 28 Oct 2025 13:22:33 +0100 Subject: [PATCH 38/67] UPSTREAM: rust: pwm: Add module_pwm_platform_driver! macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rust PWM drivers using the abstractions in `kernel/pwm.rs` typically call C functions (like `pwmchip_alloc`, `__pwmchip_add`, etc.) that are exported to the `PWM` C symbol namespace. With the introduction of `imports_ns` support in the `module!` macro, every PWM driver would need to manually include `imports_ns: ["PWM"]` in its module declaration. To simplify this for driver authors and ensure consistency, introduce a new helper macro `module_pwm_platform_driver!` in `pwm.rs`. This macro wraps the standard `module_platform_driver!`, forwards all user provided arguments using the `($($user_args:tt)*)` pattern, and automatically injects the `imports_ns: ["PWM"]` declaration. This follows the pattern used in other subsystems (e.g., `module_pci_driver!`) to provide specialized module registration helpers. It makes writing PWM drivers slightly simpler and less error prone regarding namespace imports. Signed-off-by: Michal Wilczynski Reviewed-by: Elle Rhumsaa Link: https://patch.msgid.link/20251028-pwm_fixes-v1-2-25a532d31998@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit 264b501bb40dd22e8c4ab2c8a3378e32c2e04ec6) Signed-off-by: Han Gao --- rust/kernel/pwm.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs index 79fbb13cd47f75..6f2f78c687d5b9 100644 --- a/rust/kernel/pwm.rs +++ b/rust/kernel/pwm.rs @@ -760,3 +760,26 @@ impl Drop for Registration { unsafe { bindings::pwmchip_remove(chip_raw); } } } + +/// Declares a kernel module that exposes a single PWM driver. +/// +/// # Examples +/// +///```ignore +/// kernel::module_pwm_platform_driver! { +/// type: MyDriver, +/// name: "Module name", +/// authors: ["Author name"], +/// description: "Description", +/// license: "GPL v2", +/// } +///``` +#[macro_export] +macro_rules! module_pwm_platform_driver { + ($($user_args:tt)*) => { + $crate::module_platform_driver! { + $($user_args)* + imports_ns: ["PWM"], + } + }; +} From 1a140b3d75965b56ea698ec5e1550d9946c6b581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 25 Oct 2025 14:23:56 +0200 Subject: [PATCH 39/67] UPSTREAM: rust: pwm: Drop wrapping of PWM polarity and state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were introduced and used in an earlier revision of the patch that became commit fb3957af9ec6 ("pwm: Add Rust driver for T-HEAD TH1520 SoC"). The variant that was actually applied sticks to the modern waveform abstraction only (and other drivers are supposed to do that, too), so they can be dropped. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20251025122359.361372-2-u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König (cherry picked from commit a69a54f8dffb105b2df2e606b4c9f61127d006ac) Signed-off-by: Han Gao --- rust/kernel/pwm.rs | 56 +--------------------------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs index 6f2f78c687d5b9..b19661b83b0f3e 100644 --- a/rust/kernel/pwm.rs +++ b/rust/kernel/pwm.rs @@ -15,38 +15,7 @@ use crate::{ prelude::*, types::{ARef, AlwaysRefCounted, Opaque}, }; -use core::{convert::TryFrom, marker::PhantomData, ptr::NonNull}; - -/// PWM polarity. Mirrors [`enum pwm_polarity`](srctree/include/linux/pwm.h). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Polarity { - /// Normal polarity (duty cycle defines the high period of the signal). - Normal, - - /// Inversed polarity (duty cycle defines the low period of the signal). - Inversed, -} - -impl TryFrom for Polarity { - type Error = Error; - - fn try_from(polarity: bindings::pwm_polarity) -> Result { - match polarity { - bindings::pwm_polarity_PWM_POLARITY_NORMAL => Ok(Polarity::Normal), - bindings::pwm_polarity_PWM_POLARITY_INVERSED => Ok(Polarity::Inversed), - _ => Err(EINVAL), - } - } -} - -impl From for bindings::pwm_polarity { - fn from(polarity: Polarity) -> Self { - match polarity { - Polarity::Normal => bindings::pwm_polarity_PWM_POLARITY_NORMAL, - Polarity::Inversed => bindings::pwm_polarity_PWM_POLARITY_INVERSED, - } - } -} +use core::{marker::PhantomData, ptr::NonNull}; /// Represents a PWM waveform configuration. /// Mirrors struct [`struct pwm_waveform`](srctree/include/linux/pwm.h). @@ -89,22 +58,6 @@ impl From for bindings::pwm_waveform { } } -/// Wrapper for PWM state [`struct pwm_state`](srctree/include/linux/pwm.h). -#[repr(transparent)] -pub struct State(bindings::pwm_state); - -impl State { - /// Creates a `State` wrapper by taking ownership of a C `pwm_state` value. - pub(crate) fn from_c(c_state: bindings::pwm_state) -> Self { - State(c_state) - } - - /// Returns `true` if the PWM signal is enabled. - pub fn enabled(&self) -> bool { - self.0.enabled - } -} - /// Describes the outcome of a `round_waveform` operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RoundingOutcome { @@ -164,13 +117,6 @@ impl Device { Some(unsafe { CStr::from_char_ptr(label_ptr) }) } - /// Gets a copy of the current state of this PWM device. - pub fn state(&self) -> State { - // SAFETY: `self.as_raw()` gives a valid pointer. `(*self.as_raw()).state` - // is a valid `pwm_state` struct. `State::from_c` copies this data. - State::from_c(unsafe { (*self.as_raw()).state }) - } - /// Sets the PWM waveform configuration and enables the PWM signal. pub fn set_waveform(&self, wf: &Waveform, exact: bool) -> Result { let c_wf = bindings::pwm_waveform::from(*wf); From 504172b608c8bf153c1fb21fc83f6b1a9b5a6d1d Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 29 Oct 2025 19:19:40 +0100 Subject: [PATCH 40/67] UPSTREAM: rust: pwm: Fix broken intra-doc link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `rustdoc` reports a broken intra-doc link: error: unresolved link to `Devres::register` --> rust/kernel/pwm.rs:722:11 | 722 | /// via [`Devres::register`]. This ties the lifetime of the PWM chip registration | ^^^^^^^^^^^^^^^^ no item named `Devres` in scope | = note: `-D rustdoc::broken-intra-doc-links` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(rustdoc::broken_intra_doc_links)]` Thus fix it. Fixes: d8046cd50879 ("rust: pwm: Add complete abstraction layer") Signed-off-by: Miguel Ojeda Link: https://patch.msgid.link/20251029181940.780629-1-ojeda@kernel.org Signed-off-by: Uwe Kleine-König (cherry picked from commit 51b4c0f9749d96d56887896383141e97916ac91b) Signed-off-by: Han Gao --- rust/kernel/pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs index b19661b83b0f3e..e6d1278d831693 100644 --- a/rust/kernel/pwm.rs +++ b/rust/kernel/pwm.rs @@ -660,7 +660,7 @@ unsafe impl Sync for Chip {} /// A resource guard that ensures `pwmchip_remove` is called on drop. /// /// This struct is intended to be managed by the `devres` framework by transferring its ownership -/// via [`Devres::register`]. This ties the lifetime of the PWM chip registration +/// via [`devres::register`]. This ties the lifetime of the PWM chip registration /// to the lifetime of the underlying device. pub struct Registration { chip: ARef>, From d3fc2cdcb3168db7c9b05446d03532fde04f38e5 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:04 +0200 Subject: [PATCH 41/67] UPSTREAM: pwm: Add Rust driver for T-HEAD TH1520 SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a PWM driver for the T-HEAD TH1520 SoC, written in Rust and utilizing the safe PWM abstractions from the preceding commit. The driver implements the pwm::PwmOps trait using the modern waveform API (round_waveform_tohw, write_waveform, etc.) to support configuration of period, duty cycle, and polarity for the TH1520's PWM channels. Resource management is handled using idiomatic Rust patterns. The PWM chip object is allocated via pwm::Chip::new and its registration with the PWM core is managed by the pwm::Registration RAII guard. This ensures pwmchip_remove is always called when the driver unbinds, preventing resource leaks. Device managed resources are used for the MMIO region, and the clock lifecycle is correctly managed in the driver's private data Drop implementation. The driver's core logic is written entirely in safe Rust, with no unsafe blocks, except for the Send and Sync implementations for the driver data, which are explained in the comments. Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-4-a5df2405d2bd@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit e03724aac758f71c6cda208ea3d1afd0bbb6d9aa) Signed-off-by: Han Gao --- MAINTAINERS | 1 + drivers/pwm/Kconfig | 11 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm_th1520.rs | 378 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 391 insertions(+) create mode 100644 drivers/pwm/pwm_th1520.rs diff --git a/MAINTAINERS b/MAINTAINERS index d3642ea24db508..9fd5c1bf677099 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22269,6 +22269,7 @@ F: drivers/pinctrl/pinctrl-th1520.c F: drivers/pmdomain/thead/ F: drivers/power/reset/th1520-aon-reboot.c F: drivers/power/sequencing/pwrseq-thead-gpu.c +F: drivers/pwm/pwm_th1520.rs F: drivers/reset/reset-th1520.c F: drivers/usb/dwc3/dwc3-thead.c F: include/dt-bindings/clock/thead,th1520-clk-ap.h diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index d87c4521268c18..0b47456e2d57bb 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -748,6 +748,17 @@ config PWM_TEGRA To compile this driver as a module, choose M here: the module will be called pwm-tegra. +config PWM_TH1520 + tristate "TH1520 PWM support" + depends on RUST + select RUST_PWM_ABSTRACTIONS + help + This option enables the driver for the PWM controller found on the + T-HEAD TH1520 SoC. + + To compile this driver as a module, choose M here; the module + will be called pwm-th1520. If you are unsure, say N. + config PWM_TIECAP tristate "ECAP PWM support" depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index dfa8b4966ee19a..aed403f0a42b33 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o +obj-$(CONFIG_PWM_TH1520) += pwm_th1520.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs new file mode 100644 index 00000000000000..0ad38b78be854a --- /dev/null +++ b/drivers/pwm/pwm_th1520.rs @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2025 Samsung Electronics Co., Ltd. +// Author: Michal Wilczynski + +//! Rust T-HEAD TH1520 PWM driver +//! +//! Limitations: +//! - The period and duty cycle are controlled by 32-bit hardware registers, +//! limiting the maximum resolution. +//! - The driver supports continuous output mode only; one-shot mode is not +//! implemented. +//! - The controller hardware provides up to 6 PWM channels. +//! - Reconfiguration is glitch free - new period and duty cycle values are +//! latched and take effect at the start of the next period. +//! - Polarity is handled via a simple hardware inversion bit; arbitrary +//! duty cycle offsets are not supported. +//! - Disabling a channel is achieved by configuring its duty cycle to zero to +//! produce a static low output. Clearing the `start` does not reliably +//! force the static inactive level defined by the `INACTOUT` bit. Hence +//! this method is not used in this driver. +//! + +use core::ops::Deref; +use kernel::{ + c_str, + clk::Clk, + device::{Bound, Core, Device}, + devres, + io::mem::IoMem, + of, platform, + prelude::*, + pwm, time, +}; + +const TH1520_MAX_PWM_NUM: u32 = 6; + +// Register offsets +const fn th1520_pwm_chn_base(n: u32) -> usize { + (n * 0x20) as usize +} + +const fn th1520_pwm_ctrl(n: u32) -> usize { + th1520_pwm_chn_base(n) +} + +const fn th1520_pwm_per(n: u32) -> usize { + th1520_pwm_chn_base(n) + 0x08 +} + +const fn th1520_pwm_fp(n: u32) -> usize { + th1520_pwm_chn_base(n) + 0x0c +} + +// Control register bits +const TH1520_PWM_START: u32 = 1 << 0; +const TH1520_PWM_CFG_UPDATE: u32 = 1 << 2; +const TH1520_PWM_CONTINUOUS_MODE: u32 = 1 << 5; +const TH1520_PWM_FPOUT: u32 = 1 << 8; + +const TH1520_PWM_REG_SIZE: usize = 0xB0; + +fn ns_to_cycles(ns: u64, rate_hz: u64) -> u64 { + const NSEC_PER_SEC_U64: u64 = time::NSEC_PER_SEC as u64; + + (match ns.checked_mul(rate_hz) { + Some(product) => product, + None => u64::MAX, + }) / NSEC_PER_SEC_U64 +} + +fn cycles_to_ns(cycles: u64, rate_hz: u64) -> u64 { + const NSEC_PER_SEC_U64: u64 = time::NSEC_PER_SEC as u64; + + // TODO: Replace with a kernel helper like `mul_u64_u64_div_u64_roundup` + // once available in Rust. + let numerator = cycles + .saturating_mul(NSEC_PER_SEC_U64) + .saturating_add(rate_hz - 1); + + numerator / rate_hz +} + +/// Hardware-specific waveform representation for TH1520. +#[derive(Copy, Clone, Debug, Default)] +struct Th1520WfHw { + period_cycles: u32, + duty_cycles: u32, + ctrl_val: u32, + enabled: bool, +} + +/// The driver's private data struct. It holds all necessary devres managed resources. +#[pin_data(PinnedDrop)] +struct Th1520PwmDriverData { + #[pin] + iomem: devres::Devres>, + clk: Clk, +} + +// This `unsafe` implementation is a temporary necessity because the underlying `kernel::clk::Clk` +// type does not yet expose `Send` and `Sync` implementations. This block should be removed +// as soon as the clock abstraction provides these guarantees directly. +// TODO: Remove those unsafe impl's when Clk will support them itself. + +// SAFETY: The `devres` framework requires the driver's private data to be `Send` and `Sync`. +// We can guarantee this because the PWM core synchronizes all callbacks, preventing concurrent +// access to the contained `iomem` and `clk` resources. +unsafe impl Send for Th1520PwmDriverData {} + +// SAFETY: The same reasoning applies as for `Send`. The PWM core's synchronization +// guarantees that it is safe for multiple threads to have shared access (`&self`) +// to the driver data during callbacks. +unsafe impl Sync for Th1520PwmDriverData {} + +impl pwm::PwmOps for Th1520PwmDriverData { + type WfHw = Th1520WfHw; + + fn round_waveform_tohw( + chip: &pwm::Chip, + _pwm: &pwm::Device, + wf: &pwm::Waveform, + ) -> Result> { + let data = chip.drvdata(); + let mut status = 0; + + if wf.period_length_ns == 0 { + dev_dbg!(chip.device(), "Requested period is 0, disabling PWM.\n"); + + return Ok(pwm::RoundedWaveform { + status: 0, + hardware_waveform: Th1520WfHw { + enabled: false, + ..Default::default() + }, + }); + } + + let rate_hz = data.clk.rate().as_hz() as u64; + + let mut period_cycles = ns_to_cycles(wf.period_length_ns, rate_hz).min(u64::from(u32::MAX)); + + if period_cycles == 0 { + dev_dbg!( + chip.device(), + "Requested period {} ns is too small for clock rate {} Hz, rounding up.\n", + wf.period_length_ns, + rate_hz + ); + + period_cycles = 1; + status = 1; + } + + let mut duty_cycles = ns_to_cycles(wf.duty_length_ns, rate_hz).min(u64::from(u32::MAX)); + + let mut ctrl_val = TH1520_PWM_CONTINUOUS_MODE; + + let is_inversed = wf.duty_length_ns > 0 + && wf.duty_offset_ns > 0 + && wf.duty_offset_ns >= wf.period_length_ns.saturating_sub(wf.duty_length_ns); + if is_inversed { + duty_cycles = period_cycles - duty_cycles; + } else { + ctrl_val |= TH1520_PWM_FPOUT; + } + + let wfhw = Th1520WfHw { + // The cast is safe because the value was clamped with `.min(u64::from(u32::MAX))`. + period_cycles: period_cycles as u32, + duty_cycles: duty_cycles as u32, + ctrl_val, + enabled: true, + }; + + dev_dbg!( + chip.device(), + "Requested: {}/{} ns [+{} ns] -> HW: {}/{} cycles, ctrl 0x{:x}, rate {} Hz\n", + wf.duty_length_ns, + wf.period_length_ns, + wf.duty_offset_ns, + wfhw.duty_cycles, + wfhw.period_cycles, + wfhw.ctrl_val, + rate_hz + ); + + Ok(pwm::RoundedWaveform { + status: status, + hardware_waveform: wfhw, + }) + } + + fn round_waveform_fromhw( + chip: &pwm::Chip, + _pwm: &pwm::Device, + wfhw: &Self::WfHw, + wf: &mut pwm::Waveform, + ) -> Result { + let data = chip.drvdata(); + let rate_hz = data.clk.rate().as_hz() as u64; + + if wfhw.period_cycles == 0 { + dev_dbg!(chip.device(), "HW state has zero period, reporting as disabled.\n"); + *wf = pwm::Waveform::default(); + return Ok(()); + } + + wf.period_length_ns = cycles_to_ns(u64::from(wfhw.period_cycles), rate_hz); + + let duty_cycles = u64::from(wfhw.duty_cycles); + + if (wfhw.ctrl_val & TH1520_PWM_FPOUT) != 0 { + wf.duty_length_ns = cycles_to_ns(duty_cycles, rate_hz); + wf.duty_offset_ns = 0; + } else { + let period_cycles = u64::from(wfhw.period_cycles); + let original_duty_cycles = period_cycles.saturating_sub(duty_cycles); + + // For an inverted signal, `duty_length_ns` is the high time (period - low_time). + wf.duty_length_ns = cycles_to_ns(original_duty_cycles, rate_hz); + // The offset is the initial low time, which is what the hardware register provides. + wf.duty_offset_ns = cycles_to_ns(duty_cycles, rate_hz); + } + + Ok(()) + } + + fn read_waveform( + chip: &pwm::Chip, + pwm: &pwm::Device, + parent_dev: &Device, + ) -> Result { + let data = chip.drvdata(); + let hwpwm = pwm.hwpwm(); + let iomem_accessor = data.iomem.access(parent_dev)?; + let iomap = iomem_accessor.deref(); + + let ctrl = iomap.try_read32(th1520_pwm_ctrl(hwpwm))?; + let period_cycles = iomap.try_read32(th1520_pwm_per(hwpwm))?; + let duty_cycles = iomap.try_read32(th1520_pwm_fp(hwpwm))?; + + let wfhw = Th1520WfHw { + period_cycles, + duty_cycles, + ctrl_val: ctrl, + enabled: duty_cycles != 0, + }; + + dev_dbg!( + chip.device(), + "PWM-{}: read_waveform: Read hw state - period: {}, duty: {}, ctrl: 0x{:x}, enabled: {}", + hwpwm, + wfhw.period_cycles, + wfhw.duty_cycles, + wfhw.ctrl_val, + wfhw.enabled + ); + + Ok(wfhw) + } + + fn write_waveform( + chip: &pwm::Chip, + pwm: &pwm::Device, + wfhw: &Self::WfHw, + parent_dev: &Device, + ) -> Result { + let data = chip.drvdata(); + let hwpwm = pwm.hwpwm(); + let iomem_accessor = data.iomem.access(parent_dev)?; + let iomap = iomem_accessor.deref(); + let duty_cycles = iomap.try_read32(th1520_pwm_fp(hwpwm))?; + let was_enabled = duty_cycles != 0; + + if !wfhw.enabled { + dev_dbg!(chip.device(), "PWM-{}: Disabling channel.\n", hwpwm); + if was_enabled { + iomap.try_write32(wfhw.ctrl_val, th1520_pwm_ctrl(hwpwm))?; + iomap.try_write32(0, th1520_pwm_fp(hwpwm))?; + iomap.try_write32(wfhw.ctrl_val | TH1520_PWM_CFG_UPDATE, th1520_pwm_ctrl(hwpwm))?; + } + return Ok(()); + } + + iomap.try_write32(wfhw.ctrl_val, th1520_pwm_ctrl(hwpwm))?; + iomap.try_write32(wfhw.period_cycles, th1520_pwm_per(hwpwm))?; + iomap.try_write32(wfhw.duty_cycles, th1520_pwm_fp(hwpwm))?; + iomap.try_write32(wfhw.ctrl_val | TH1520_PWM_CFG_UPDATE, th1520_pwm_ctrl(hwpwm))?; + + // The `TH1520_PWM_START` bit must be written in a separate, final transaction, and + // only when enabling the channel from a disabled state. + if !was_enabled { + iomap.try_write32(wfhw.ctrl_val | TH1520_PWM_START, th1520_pwm_ctrl(hwpwm))?; + } + + dev_dbg!( + chip.device(), + "PWM-{}: Wrote {}/{} cycles", + hwpwm, + wfhw.duty_cycles, + wfhw.period_cycles, + ); + + Ok(()) + } +} + +#[pinned_drop] +impl PinnedDrop for Th1520PwmDriverData { + fn drop(self: Pin<&mut Self>) { + self.clk.disable_unprepare(); + } +} + +struct Th1520PwmPlatformDriver; + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + ::IdInfo, + [(of::DeviceId::new(c_str!("thead,th1520-pwm")), ())] +); + +impl platform::Driver for Th1520PwmPlatformDriver { + type IdInfo = (); + const OF_ID_TABLE: Option> = Some(&OF_TABLE); + + fn probe( + pdev: &platform::Device, + _id_info: Option<&Self::IdInfo>, + ) -> Result>> { + let dev = pdev.as_ref(); + let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; + + let clk = Clk::get(dev, None)?; + + clk.prepare_enable()?; + + // TODO: Get exclusive ownership of the clock to prevent rate changes. + // The Rust equivalent of `clk_rate_exclusive_get()` is not yet available. + // This should be updated once it is implemented. + let rate_hz = clk.rate().as_hz(); + if rate_hz == 0 { + dev_err!(dev, "Clock rate is zero\n"); + return Err(EINVAL); + } + + if rate_hz > time::NSEC_PER_SEC as usize { + dev_err!( + dev, + "Clock rate {} Hz is too high, not supported.\n", + rate_hz + ); + return Err(EINVAL); + } + + let chip = pwm::Chip::new( + dev, + TH1520_MAX_PWM_NUM, + try_pin_init!(Th1520PwmDriverData { + iomem <- request.iomap_sized::(), + clk <- clk, + }), + )?; + + pwm::Registration::register(dev, chip)?; + + Ok(KBox::new(Th1520PwmPlatformDriver, GFP_KERNEL)?.into()) + } +} + +kernel::module_platform_driver! { + type: Th1520PwmPlatformDriver, + name: "pwm-th1520", + authors: ["Michal Wilczynski "], + description: "T-HEAD TH1520 PWM driver", + license: "GPL v2", +} From 6e92255235f7c52e97f9d8e5b2ce305063b7cd2b Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:05 +0200 Subject: [PATCH 42/67] UPSTREAM: dt-bindings: pwm: thead: Add T-HEAD TH1520 PWM controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Device Tree binding documentation for the T-HEAD TH1520 SoC PWM controller. Reviewed-by: Krzysztof Kozlowski Acked-by: Drew Fustini Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-5-a5df2405d2bd@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit a367b64ba498a7eac34af3a67ce59317066b2779) Signed-off-by: Han Gao --- .../bindings/pwm/thead,th1520-pwm.yaml | 48 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml new file mode 100644 index 00000000000000..855aec59ac53c4 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD TH1520 PWM controller + +maintainers: + - Michal Wilczynski + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + const: thead,th1520-pwm + + reg: + maxItems: 1 + + clocks: + items: + - description: SoC PWM clock + + "#pwm-cells": + const: 3 + +required: + - compatible + - reg + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + pwm@ffec01c000 { + compatible = "thead,th1520-pwm"; + reg = <0xff 0xec01c000 0x0 0x4000>; + clocks = <&clk CLK_PWM>; + #pwm-cells = <3>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 9fd5c1bf677099..c80698be337429 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22258,6 +22258,7 @@ F: Documentation/devicetree/bindings/firmware/thead,th1520-aon.yaml F: Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml F: Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml F: Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml +F: Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml F: Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml F: arch/riscv/boot/dts/thead/ F: drivers/clk/thead/clk-th1520-ap.c From 48b3d3003777e207a1967b0907049c70a51408e1 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 29 Oct 2025 19:25:02 +0100 Subject: [PATCH 43/67] UPSTREAM: pwm: Fix Rust formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do our best to keep the repository `rustfmt`-clean [1], thus run the tool to fix the formatting issue. A trailing empty comment [2] is added in order to preserve the wanted style for imports (otherwise the tool will compact the first two items). Link: https://rust-for-linux.com/contributing#submit-checklist-addendum [1] Link: https://docs.kernel.org/rust/coding-guidelines.html#style-formatting [2] Fixes: d8046cd50879 ("rust: pwm: Add complete abstraction layer") Fixes: 7b3dce814a15 ("rust: pwm: Add Kconfig and basic data structures") Fixes: e03724aac758 ("pwm: Add Rust driver for T-HEAD TH1520 SoC") Signed-off-by: Miguel Ojeda Link: https://patch.msgid.link/20251029182502.783392-1-ojeda@kernel.org Signed-off-by: Uwe Kleine-König (cherry picked from commit 6fe9e919c144f1296d38e2abb10c7ac4320aa7fa) Signed-off-by: Han Gao --- drivers/pwm/pwm_th1520.rs | 15 ++++++++++--- rust/kernel/lib.rs | 4 ++-- rust/kernel/pwm.rs | 46 +++++++++++++++++++++------------------ 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index 0ad38b78be854a..ee2a6d573bc23d 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -200,7 +200,10 @@ impl pwm::PwmOps for Th1520PwmDriverData { let rate_hz = data.clk.rate().as_hz() as u64; if wfhw.period_cycles == 0 { - dev_dbg!(chip.device(), "HW state has zero period, reporting as disabled.\n"); + dev_dbg!( + chip.device(), + "HW state has zero period, reporting as disabled.\n" + ); *wf = pwm::Waveform::default(); return Ok(()); } @@ -277,7 +280,10 @@ impl pwm::PwmOps for Th1520PwmDriverData { if was_enabled { iomap.try_write32(wfhw.ctrl_val, th1520_pwm_ctrl(hwpwm))?; iomap.try_write32(0, th1520_pwm_fp(hwpwm))?; - iomap.try_write32(wfhw.ctrl_val | TH1520_PWM_CFG_UPDATE, th1520_pwm_ctrl(hwpwm))?; + iomap.try_write32( + wfhw.ctrl_val | TH1520_PWM_CFG_UPDATE, + th1520_pwm_ctrl(hwpwm), + )?; } return Ok(()); } @@ -285,7 +291,10 @@ impl pwm::PwmOps for Th1520PwmDriverData { iomap.try_write32(wfhw.ctrl_val, th1520_pwm_ctrl(hwpwm))?; iomap.try_write32(wfhw.period_cycles, th1520_pwm_per(hwpwm))?; iomap.try_write32(wfhw.duty_cycles, th1520_pwm_fp(hwpwm))?; - iomap.try_write32(wfhw.ctrl_val | TH1520_PWM_CFG_UPDATE, th1520_pwm_ctrl(hwpwm))?; + iomap.try_write32( + wfhw.ctrl_val | TH1520_PWM_CFG_UPDATE, + th1520_pwm_ctrl(hwpwm), + )?; // The `TH1520_PWM_START` bit must be written in a separate, final transaction, and // only when enabling the channel from a disabled state. diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 68c71d888fdb84..584aa3282029c5 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -121,6 +121,8 @@ pub mod prelude; pub mod print; pub mod processor; pub mod ptr; +#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)] +pub mod pwm; pub mod rbtree; pub mod regulator; pub mod revocable; @@ -129,8 +131,6 @@ pub mod security; pub mod seq_file; pub mod sizes; mod static_assert; -#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)] -pub mod pwm; #[doc(hidden)] pub mod std_vendor; pub mod str; diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs index e6d1278d831693..cb00f8a8765c8e 100644 --- a/rust/kernel/pwm.rs +++ b/rust/kernel/pwm.rs @@ -13,7 +13,7 @@ use crate::{ devres, error::{self, to_result}, prelude::*, - types::{ARef, AlwaysRefCounted, Opaque}, + types::{ARef, AlwaysRefCounted, Opaque}, // }; use core::{marker::PhantomData, ptr::NonNull}; @@ -109,7 +109,7 @@ impl Device { // SAFETY: self.as_raw() provides a valid pointer. let label_ptr = unsafe { (*self.as_raw()).label }; if label_ptr.is_null() { - return None + return None; } // SAFETY: label_ptr is non-null and points to a C string @@ -180,11 +180,7 @@ pub trait PwmOps: 'static + Sized { type WfHw: Copy + Default; /// Optional hook for when a PWM device is requested. - fn request( - _chip: &Chip, - _pwm: &Device, - _parent_dev: &device::Device, - ) -> Result { + fn request(_chip: &Chip, _pwm: &Device, _parent_dev: &device::Device) -> Result { Ok(()) } @@ -310,7 +306,9 @@ impl Adapter { // Now, call the original release function to free the `pwm_chip` itself. // SAFETY: `dev` is the valid pointer passed into this callback, which is // the expected argument for `pwmchip_release`. - unsafe { bindings::pwmchip_release(dev); } + unsafe { + bindings::pwmchip_release(dev); + } } /// # Safety @@ -593,9 +591,8 @@ impl Chip { ) -> Result> { let sizeof_priv = core::mem::size_of::(); // SAFETY: `pwmchip_alloc` allocates memory for the C struct and our private data. - let c_chip_ptr_raw = unsafe { - bindings::pwmchip_alloc(parent_dev.as_raw(), num_channels, sizeof_priv) - }; + let c_chip_ptr_raw = + unsafe { bindings::pwmchip_alloc(parent_dev.as_raw(), num_channels, sizeof_priv) }; let c_chip_ptr: *mut bindings::pwm_chip = error::from_err_ptr(c_chip_ptr_raw)?; @@ -607,12 +604,16 @@ impl Chip { unsafe { data.__pinned_init(drvdata_ptr.cast())? }; // SAFETY: `c_chip_ptr` points to a valid chip. - unsafe { (*c_chip_ptr).dev.release = Some(Adapter::::release_callback); } + unsafe { + (*c_chip_ptr).dev.release = Some(Adapter::::release_callback); + } // SAFETY: `c_chip_ptr` points to a valid chip. // The `Adapter`'s `VTABLE` has a 'static lifetime, so the pointer // returned by `as_raw()` is always valid. - unsafe { (*c_chip_ptr).ops = Adapter::::VTABLE.as_raw(); } + unsafe { + (*c_chip_ptr).ops = Adapter::::VTABLE.as_raw(); + } // Cast the `*mut bindings::pwm_chip` to `*mut Chip`. This is valid because // `Chip` is `repr(transparent)` over `Opaque`, and @@ -632,7 +633,9 @@ unsafe impl AlwaysRefCounted for Chip { fn inc_ref(&self) { // SAFETY: `self.0.get()` points to a valid `pwm_chip` because `self` exists. // The embedded `dev` is valid. `get_device` increments its refcount. - unsafe { bindings::get_device(&raw mut (*self.0.get()).dev); } + unsafe { + bindings::get_device(&raw mut (*self.0.get()).dev); + } } #[inline] @@ -641,7 +644,9 @@ unsafe impl AlwaysRefCounted for Chip { // SAFETY: `obj` is a valid pointer to a `Chip` (and thus `bindings::pwm_chip`) // with a non-zero refcount. `put_device` handles decrement and final release. - unsafe { bindings::put_device(&raw mut (*c_chip_ptr).dev); } + unsafe { + bindings::put_device(&raw mut (*c_chip_ptr).dev); + } } } @@ -673,11 +678,8 @@ impl Registration { /// to the parent device. /// On unbind of the parent device, the `devres` entry will be dropped, automatically /// calling `pwmchip_remove`. This function should be called from the driver's `probe`. - pub fn register( - dev: &device::Device, - chip: ARef>, - ) -> Result { - let chip_parent = chip.device().parent().ok_or(EINVAL)?; + pub fn register(dev: &device::Device, chip: ARef>) -> Result { + let chip_parent = chip.device().parent().ok_or(EINVAL)?; if dev.as_raw() != chip_parent.as_raw() { return Err(EINVAL); } @@ -703,7 +705,9 @@ impl Drop for Registration { // SAFETY: `chip_raw` points to a chip that was successfully registered. // `bindings::pwmchip_remove` is the correct C function to unregister it. // This `drop` implementation is called automatically by `devres` on driver unbind. - unsafe { bindings::pwmchip_remove(chip_raw); } + unsafe { + bindings::pwmchip_remove(chip_raw); + } } } From 9ce7daf814a96e3ac6464fe4228f09346d1cf6b4 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Tue, 28 Oct 2025 13:22:35 +0100 Subject: [PATCH 44/67] UPSTREAM: pwm: th1520: Fix clippy warning for redundant struct field init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clippy warns about redundant struct field initialization when the field name and the variable name are the same (e.g., `status: status`). No functional change. Signed-off-by: Michal Wilczynski Reviewed-by: Elle Rhumsaa Link: https://patch.msgid.link/20251028-pwm_fixes-v1-4-25a532d31998@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit 26dcb42086d401373b9e09b7f83357e8b9af6b55) Signed-off-by: Han Gao --- drivers/pwm/pwm_th1520.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index ee2a6d573bc23d..b2d83c121c5c72 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -185,7 +185,7 @@ impl pwm::PwmOps for Th1520PwmDriverData { ); Ok(pwm::RoundedWaveform { - status: status, + status, hardware_waveform: wfhw, }) } From c78b86623581ce9eac93004178076c790dd76744 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Tue, 28 Oct 2025 13:22:34 +0100 Subject: [PATCH 45/67] UPSTREAM: pwm: th1520: Use module_pwm_platform_driver! macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `pwm_th1520` Rust driver calls C functions from the `PWM` namespace, triggering `modpost` warnings due to missing namespace import declarations in its `.modinfo` section. Fix these warnings and simplify the module declaration by switching from the generic `kernel::module_platform_driver!` macro to the newly introduced PWM-specific `kernel::module_pwm_platform_driver!` macro. The new macro automatically handles the required `imports_ns: ["PWM"]` declaration. Signed-off-by: Michal Wilczynski Reviewed-by: Troy Mitchell Reviewed-by: Elle Rhumsaa Link: https://patch.msgid.link/20251028-pwm_fixes-v1-3-25a532d31998@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit 9075ceeadac3e4e4fd906cd84f1ec537442c59be) Signed-off-by: Han Gao --- drivers/pwm/pwm_th1520.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index b2d83c121c5c72..955c359b07fb4f 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -378,7 +378,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { } } -kernel::module_platform_driver! { +kernel::module_pwm_platform_driver! { type: Th1520PwmPlatformDriver, name: "pwm-th1520", authors: ["Michal Wilczynski "], From 1e7d6ef373740b451c994e3b8c6b98f58407c50b Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Tue, 2 Dec 2025 13:25:07 +0800 Subject: [PATCH 46/67] UPSTREAM: lib/crypto: riscv/chacha: Avoid s0/fp register In chacha_zvkb, avoid using the s0 register, which is the frame pointer, by reallocating KEY0 to t5. This makes stack traces available if e.g. a crash happens in chacha_zvkb. No frame pointer maintenance is otherwise required since this is a leaf function. Signed-off-by: Vivian Wang Fixes: bb54668837a0 ("crypto: riscv - add vector crypto accelerated ChaCha20") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20251202-riscv-chacha_zvkb-fp-v2-1-7bd00098c9dc@iscas.ac.cn Signed-off-by: Eric Biggers (cherry picked from commit 43169328c7b4623b54b7713ec68479cebda5465f) Signed-off-by: Han Gao --- lib/crypto/riscv/chacha-riscv64-zvkb.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/crypto/riscv/chacha-riscv64-zvkb.S b/lib/crypto/riscv/chacha-riscv64-zvkb.S index b777d0b4e37969..3d183ec818f52a 100644 --- a/lib/crypto/riscv/chacha-riscv64-zvkb.S +++ b/lib/crypto/riscv/chacha-riscv64-zvkb.S @@ -60,7 +60,8 @@ #define VL t2 #define STRIDE t3 #define ROUND_CTR t4 -#define KEY0 s0 +#define KEY0 t5 +// Avoid s0/fp to allow for unwinding #define KEY1 s1 #define KEY2 s2 #define KEY3 s3 @@ -143,7 +144,6 @@ // The updated 32-bit counter is written back to state->x[12] before returning. SYM_FUNC_START(chacha_zvkb) addi sp, sp, -96 - sd s0, 0(sp) sd s1, 8(sp) sd s2, 16(sp) sd s3, 24(sp) @@ -280,7 +280,6 @@ SYM_FUNC_START(chacha_zvkb) bnez NBLOCKS, .Lblock_loop sw COUNTER, 48(STATEP) - ld s0, 0(sp) ld s1, 8(sp) ld s2, 16(sp) ld s3, 24(sp) From a656152286b04a91b0eb3cc80ab03f97ebec2ded Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Tue, 9 Dec 2025 21:06:03 +0100 Subject: [PATCH 47/67] UPSTREAM: pwm: th1520: Fix missing Kconfig dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver fails to build on configurations lacking COMMON_CLK (missing clk::Clk) or HAS_IOMEM (incomplete `pwm_chip` struct on UML). Add dependencies on ARCH_THEAD and HAS_IOMEM, and add COMMON_CLK to ensure correct compilation and platform targeting. Reported-by: Markus Probst Closes: https://lore.kernel.org/all/a66b337528d700ae92d7940a04c59206e06a8495.camel@posteo.de/ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512020957.PqnHfe7C-lkp@intel.com/ Fixes: e03724aac758 ("pwm: Add Rust driver for T-HEAD TH1520 SoC") Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20251209-fix_deps_pwm-v1-1-f7ed8bd1bd3d@samsung.com Signed-off-by: Uwe Kleine-König (cherry picked from commit 3c180003dffbc252a72dec4f0c697e12922e0417) Signed-off-by: Han Gao --- drivers/pwm/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 0b47456e2d57bb..a2e5b73799513a 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -750,7 +750,9 @@ config PWM_TEGRA config PWM_TH1520 tristate "TH1520 PWM support" + depends on ARCH_THEAD || COMPILE_TEST depends on RUST + depends on HAS_IOMEM && COMMON_CLK select RUST_PWM_ABSTRACTIONS help This option enables the driver for the PWM controller found on the From 54658f99110622c215d4988f28753aa244a34e5d Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:47:52 +0800 Subject: [PATCH 48/67] Revert "XUANTIE: riscv: dts: thead: Add TH1520 USB nodes" This reverts commit d6d5cd5f71fdd2933cf849feafa280df187cde1a. --- arch/riscv/boot/dts/thead/th1520.dtsi | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 0502e4661b12db..cb057dcf2f659c 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -728,29 +728,6 @@ #pwm-cells = <3>; }; - misc_sysreg: misc_sysreg@ffec02c000 { - compatible = "thead,th1520-misc-sysreg", "syscon"; - reg = <0xff 0xec02c000 0x0 0x1000>; - }; - - usb: usb@ffec03f000 { - compatible = "thead,th1520-usb"; - reg = <0xff 0xec03f000 0x0 0x1000>; - thead,misc-sysreg = <&misc_sysreg>; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - usb_dwc3: usb@ffe7040000 { - compatible = "snps,dwc3"; - reg = <0xff 0xe7040000 0x0 0x10000>; - interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; - dr_mode = "host"; - snps,usb3_lpm_capable; - status = "disabled"; - }; - }; - dmac0: dma-controller@ffefc00000 { compatible = "snps,axi-dma-1.01a"; reg = <0xff 0xefc00000 0x0 0x1000>; From 8683e232fcf5e12f2aac9376ef1dbd886e285734 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:48:39 +0800 Subject: [PATCH 49/67] Revert "XUANTIE: riscv: dts: thead: Add TH1520 I2C nodes" This reverts commit cfb8f13d395c69a1c10402b94bb135642dcaa769. --- arch/riscv/boot/dts/thead/th1520.dtsi | 50 --------------------------- 1 file changed, 50 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index cb057dcf2f659c..c2f4024c48f7c3 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -458,36 +458,6 @@ status = "disabled"; }; - i2c0: i2c@ffe7f20000 { - compatible = "snps,designware-i2c"; - reg = <0xff 0xe7f20000 0x0 0x1000>; - clocks = <&clk CLK_I2C0>; - interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c1: i2c@ffe7f24000 { - compatible = "snps,designware-i2c"; - reg = <0xff 0xe7f24000 0x0 0x1000>; - clocks = <&clk CLK_I2C1>; - interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c4: i2c@ffe7f28000 { - compatible = "snps,designware-i2c"; - reg = <0xff 0xe7f28000 0x0 0x1000>; - clocks = <&clk CLK_I2C4>; - interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - gpio@ffe7f34000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xe7f34000 0x0 0x1000>; @@ -586,16 +556,6 @@ thead,pad-group = <3>; }; - i2c2: i2c@ffec00c000 { - compatible = "snps,designware-i2c"; - reg = <0xff 0xec00c000 0x0 0x1000>; - clocks = <&clk CLK_I2C2>; - interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - uart2: serial@ffec010000 { compatible = "snps,dw-apb-uart"; reg = <0xff 0xec010000 0x0 0x4000>; @@ -711,16 +671,6 @@ }; }; - i2c3: i2c@ffec014000 { - compatible = "snps,designware-i2c"; - reg = <0xff 0xec014000 0x0 0x1000>; - clocks = <&clk CLK_I2C3>; - interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - pwm: pwm@ffec01c000 { compatible = "thead,th1520-pwm"; reg = <0xff 0xec01c000 0x0 0x4000>; From c6a0bcdd974cb71ee6b540b9be405c80a51d29f7 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:49:09 +0800 Subject: [PATCH 50/67] Revert "XUANTIE: riscv: dts: thead: Add TH1520 PWM node" This reverts commit 25001ec7a1287cf9bbc4f46b7ee04ac1b005a519. --- arch/riscv/boot/dts/thead/th1520.dtsi | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index c2f4024c48f7c3..d3119f5283ec87 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -671,13 +671,6 @@ }; }; - pwm: pwm@ffec01c000 { - compatible = "thead,th1520-pwm"; - reg = <0xff 0xec01c000 0x0 0x4000>; - clocks = <&clk CLK_PWM>; - #pwm-cells = <3>; - }; - dmac0: dma-controller@ffefc00000 { compatible = "snps,axi-dma-1.01a"; reg = <0xff 0xefc00000 0x0 0x1000>; From af6f05550ac732eb09e8f31b22af52ce97537358 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:50:06 +0800 Subject: [PATCH 51/67] Revert "FROMLIST: riscv: dts: thead: add zfh for th1520" This reverts commit bc360e56d3e3f480535dd5106119e58cc99ad46c. --- arch/riscv/boot/dts/thead/th1520.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index d3119f5283ec87..53df776d974d9e 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -26,7 +26,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", "zfh", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <0>; @@ -55,7 +55,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", "zfh", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <1>; @@ -84,7 +84,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", "zfh", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <2>; @@ -113,7 +113,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", "zfh", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <3>; From 15720665f5e30c1c8d88e46fc509a0374504a96b Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:50:13 +0800 Subject: [PATCH 52/67] Revert "FROMLIST: riscv: dts: thead: add ziccrse for th1520" This reverts commit aed0eb5e7b9a47eba56889c094b7c48c181b89dc. --- arch/riscv/boot/dts/thead/th1520.dtsi | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 53df776d974d9e..480f152dfcfa94 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -24,10 +24,8 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", - "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", - "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <0>; i-cache-block-size = <64>; @@ -53,10 +51,8 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", - "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", - "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <1>; i-cache-block-size = <64>; @@ -82,10 +78,8 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", - "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", - "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <2>; i-cache-block-size = <64>; @@ -111,10 +105,8 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", - "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", - "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm", "xtheadvector"; thead,vlenb = <16>; reg = <3>; i-cache-block-size = <64>; From e2ce2d7977ec05b25de512f0c30332b80319227d Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:50:19 +0800 Subject: [PATCH 53/67] Revert "FROMLIST: riscv: dts: thead: add xtheadvector to the th1520 devicetree" This reverts commit 3e33b86bad62f84dff35408febc931478d7b7feb. --- arch/riscv/boot/dts/thead/th1520.dtsi | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 480f152dfcfa94..cf36572d314a88 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -25,8 +25,7 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; - thead,vlenb = <16>; + "zifencei", "zihpm"; reg = <0>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -52,8 +51,7 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; - thead,vlenb = <16>; + "zifencei", "zihpm"; reg = <1>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -79,8 +77,7 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; - thead,vlenb = <16>; + "zifencei", "zihpm"; reg = <2>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -106,8 +103,7 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; - thead,vlenb = <16>; + "zifencei", "zihpm"; reg = <3>; i-cache-block-size = <64>; i-cache-size = <65536>; From 4d64d40ad1bef6b286c62a557fed389cf8e28310 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Fri, 19 Sep 2025 04:44:47 +0800 Subject: [PATCH 54/67] UPSTREAM: riscv: dts: thead: add xtheadvector to the th1520 devicetree The th1520 support xtheadvector [1] so it can be included in the devicetree. Also include vlenb for the cpu. And set vlenb=16 [2]. This can be tested by passing the "mitigations=off" kernel parameter. Link: https://lore.kernel.org/linux-riscv/20241113-xtheadvector-v11-4-236c22791ef9@rivosinc.com/ [1] Link: https://lore.kernel.org/linux-riscv/aCO44SAoS2kIP61r@ghost/ [2] Signed-off-by: Han Gao Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini (cherry picked from commit aef6dc006696c20ccc58c4c0235a14e7b4b317a0) Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index cf36572d314a88..480f152dfcfa94 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -25,7 +25,8 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm"; + "zifencei", "zihpm", "xtheadvector"; + thead,vlenb = <16>; reg = <0>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -51,7 +52,8 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm"; + "zifencei", "zihpm", "xtheadvector"; + thead,vlenb = <16>; reg = <1>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -77,7 +79,8 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm"; + "zifencei", "zihpm", "xtheadvector"; + thead,vlenb = <16>; reg = <2>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -103,7 +106,8 @@ riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm"; + "zifencei", "zihpm", "xtheadvector"; + thead,vlenb = <16>; reg = <3>; i-cache-block-size = <64>; i-cache-size = <65536>; From e0560e22fdecdf74b62ec6e40c712dedfdae3e65 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Fri, 19 Sep 2025 04:44:48 +0800 Subject: [PATCH 55/67] UPSTREAM: riscv: dts: thead: add ziccrse for th1520 Existing rv64 hardware conforms to the rva20 profile. Ziccrse is an additional extension required by the rva20 profile, so th1520 has this extension. Signed-off-by: Han Gao Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini (cherry picked from commit bcc3b9c5de5e2a03ede1a8133c05255927d744d6) Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 480f152dfcfa94..53df776d974d9e 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -24,8 +24,10 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", + "ziccrse", "zicntr", "zicsr", + "zifencei", "zihpm", + "xtheadvector"; thead,vlenb = <16>; reg = <0>; i-cache-block-size = <64>; @@ -51,8 +53,10 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", + "ziccrse", "zicntr", "zicsr", + "zifencei", "zihpm", + "xtheadvector"; thead,vlenb = <16>; reg = <1>; i-cache-block-size = <64>; @@ -78,8 +82,10 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", + "ziccrse", "zicntr", "zicsr", + "zifencei", "zihpm", + "xtheadvector"; thead,vlenb = <16>; reg = <2>; i-cache-block-size = <64>; @@ -105,8 +111,10 @@ device_type = "cpu"; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm", "xtheadvector"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", + "ziccrse", "zicntr", "zicsr", + "zifencei", "zihpm", + "xtheadvector"; thead,vlenb = <16>; reg = <3>; i-cache-block-size = <64>; From a955ac3bb97d3470b6ab3c35c36da6036b04f7d0 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Fri, 19 Sep 2025 04:44:49 +0800 Subject: [PATCH 56/67] UPSTREAM: riscv: dts: thead: add zfh for th1520 th1520 support Zfh ISA extension. It supports the same RISC-V extensions as SG2042. commit cb074bed1186 ("riscv: dts: sophgo: add zfh for sg2042") Signed-off-by: Han Gao Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini (cherry picked from commit fac4be7b3d49ae7e32d8ae523343d7fe790772f9) Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 53df776d974d9e..d3119f5283ec87 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -26,7 +26,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", + "zifencei", "zihpm", "zfh", "xtheadvector"; thead,vlenb = <16>; reg = <0>; @@ -55,7 +55,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", + "zifencei", "zihpm", "zfh", "xtheadvector"; thead,vlenb = <16>; reg = <1>; @@ -84,7 +84,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", + "zifencei", "zihpm", "zfh", "xtheadvector"; thead,vlenb = <16>; reg = <2>; @@ -113,7 +113,7 @@ riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "ziccrse", "zicntr", "zicsr", - "zifencei", "zihpm", + "zifencei", "zihpm", "zfh", "xtheadvector"; thead,vlenb = <16>; reg = <3>; From e3e367862c21f41112264848753f699cd117dd0d Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:06 +0200 Subject: [PATCH 57/67] UPSTREAM: riscv: dts: thead: Add PWM controller node Add the Device Tree node for the T-HEAD TH1520 SoC's PWM controller. Reviewed-by: Drew Fustini Tested-by: Drew Fustini Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Signed-off-by: Drew Fustini (cherry picked from commit b6b00b220d2a052b2bec8ee7ccaf2679faef8558) Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index d3119f5283ec87..3263f4aa313cd0 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -567,6 +567,13 @@ status = "disabled"; }; + pwm: pwm@ffec01c000 { + compatible = "thead,th1520-pwm"; + reg = <0xff 0xec01c000 0x0 0x4000>; + clocks = <&clk CLK_PWM>; + #pwm-cells = <3>; + }; + clk: clock-controller@ffef010000 { compatible = "thead,th1520-clk-ap"; reg = <0xff 0xef010000 0x0 0x1000>; From 0c8efafc8d1c75c5a7e7a9e2fd1267ce5510c920 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:53:37 +0800 Subject: [PATCH 58/67] Revert "XUANTIE: riscv: dts: thead: Enable Lichee Pi 4A USB" This reverts commit 33d837191df0d73c11c8864dc1caffe8dc2f52a7. --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 59 ------------------- 1 file changed, 59 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 7a827e3b8496da..44e45b49599521 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -4,7 +4,6 @@ */ #include "th1520-lichee-module-4a.dtsi" -#include / { model = "Sipeed Lichee Pi 4A"; @@ -24,11 +23,6 @@ serial4 = &uart4; serial5 = &uart5; spi0 = &spi0; - i2c0 = &i2c0; - i2c1 = &i2c1; - i2c2 = &i2c2; - i2c3 = &i2c3; - i2c4 = &i2c4; }; chosen { @@ -55,26 +49,6 @@ cooling-levels = <0 66 196 255>; }; - hub_5v: regulator-hub_5v { - compatible = "regulator-fixed"; - regulator-name = "HUB_5V"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; - enable-active-high; - regulator-always-on; - }; - - vcc5v_usb: regulator-vcc5v_usb { - compatible = "regulator-fixed"; - regulator-name = "VCC5V_USB"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; - enable-active-high; - regulator-always-on; - }; - thermal-zones { cpu-thermal { polling-delay = <1000>; @@ -121,14 +95,6 @@ }; }; -&aogpio { - sel-usb-hub-hog { - gpio-hog; - gpios = <4 GPIO_ACTIVE_HIGH>; - output-high; - }; -}; - &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; @@ -293,28 +259,3 @@ pinctrl-0 = <&uart0_pins>; status = "okay"; }; - -&usb { - status = "okay"; -}; - -&usb_dwc3 { - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - - hub_2_0: hub@1 { - compatible = "usb2109,2817"; - reg = <1>; - peer-hub = <&hub_3_0>; - vdd-supply = <&hub_5v>; - vbus-supply = <&vcc5v_usb>; - }; - - hub_3_0: hub@2 { - compatible = "usb2109,817"; - reg = <2>; - peer-hub = <&hub_2_0>; - vbus-supply = <&vcc5v_usb>; - }; -}; From 7337b305035613047465a1e6f84c437e1bcb8f85 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:54:01 +0800 Subject: [PATCH 59/67] Revert "XUANTIE: riscv: dts: thead: Add Lichee Pi 4A IO expansions" This reverts commit 27dc939dbf812f5648db4bb200db8c29245a59c4. --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 109 ------------------ 1 file changed, 109 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 44e45b49599521..fd06c4adcb3770 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -95,76 +95,6 @@ }; }; -&i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pins>; - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - status = "okay"; - - ioexp1: gpio@18 { - compatible = "nxp,pca9557"; - reg = <0x18>; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "cam0_dvdd12", - "cam0_avdd28", - "cam0_dovdd18"; - }; -}; - -&i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c1_pins>; - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - status = "okay"; - - ioexp2: gpio@18 { - compatible = "nxp,pca9557"; - reg = <0x18>; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "", - "cam0_reset", - "cam1_reset", - "cam2_reset", - "wl_host_wake", - "bt_resetn", - "", - "bt_host_wake"; - }; -}; - -&i2c3 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c3_pins>; - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - status = "okay"; - - ioexp3: gpio@18 { - compatible = "nxp,pca9557"; - reg = <0x18>; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "tp0_rst", - "", - "", - "vcc5v_usb", - "vdd28_tp0", - "vdd33_lcd0", - "vdd18_lcd0", - "lcd0_reset"; - }; -}; - &padctrl0_apsys { fan_pins: fan-0 { pwm1-pins { @@ -178,18 +108,6 @@ }; }; - i2c3_pins: i2c3-0 { - i2c-pins { - pins = "I2C3_SCL", "I2C3_SDA"; - function = "i2c"; - bias-disable; - drive-strength = <7>; - input-enable; - input-schmitt-enable; - slew-rate = <0>; - }; - }; - uart0_pins: uart0-0 { tx-pins { pins = "UART0_TXD"; @@ -224,33 +142,6 @@ &hdmi_out_port { hdmi_out_con: endpoint { remote-endpoint = <&hdmi_con_in>; - - }; -}; - -&padctrl1_apsys { - i2c0_pins: i2c0-0 { - i2c-pins { - pins = "I2C0_SCL", "I2C0_SDA"; - function = "i2c"; - bias-disable; - drive-strength = <7>; - input-enable; - input-schmitt-enable; - slew-rate = <0>; - }; - }; - - i2c1_pins: i2c1-0 { - i2c-pins { - pins = "I2C1_SCL", "I2C1_SDA"; - function = "i2c"; - bias-disable; - drive-strength = <7>; - input-enable; - input-schmitt-enable; - slew-rate = <0>; - }; }; }; From c9c97f867a00d80b444bf32b73f06cb23ab35899 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:54:37 +0800 Subject: [PATCH 60/67] Revert "XUANTIE: riscv: dts: thead: Enable Lichee Pi 4A PWM fan" This reverts commit 4f8fb3fd42708bf91e231c7eb41a6190dab4b6a2. --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index fd06c4adcb3770..3e99f905dc316e 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -39,75 +39,9 @@ }; }; }; - - fan: pwm-fan { - pinctrl-names = "default"; - pinctrl-0 = <&fan_pins>; - compatible = "pwm-fan"; - #cooling-cells = <2>; - pwms = <&pwm 1 10000000 0>; - cooling-levels = <0 66 196 255>; - }; - - thermal-zones { - cpu-thermal { - polling-delay = <1000>; - polling-delay-passive = <1000>; - thermal-sensors = <&pvt 0>; - - trips { - trip_active0: active-0 { - temperature = <39000>; - hysteresis = <5000>; - type = "active"; - }; - - trip_active1: active-1 { - temperature = <50000>; - hysteresis = <5000>; - type = "active"; - }; - - trip_active2: active-2 { - temperature = <60000>; - hysteresis = <5000>; - type = "active"; - }; - }; - - cooling-maps { - map-active-0 { - cooling-device = <&fan 1 1>; - trip = <&trip_active0>; - }; - - map-active-1 { - cooling-device = <&fan 2 2>; - trip = <&trip_active1>; - }; - - map-active-2 { - cooling-device = <&fan 3 3>; - trip = <&trip_active2>; - }; - }; - }; - }; }; &padctrl0_apsys { - fan_pins: fan-0 { - pwm1-pins { - pins = "GPIO3_3"; /* PWM1 */ - function = "pwm"; - bias-disable; - drive-strength = <25>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - }; - uart0_pins: uart0-0 { tx-pins { pins = "UART0_TXD"; From 433028346c9b8955a8ae33ddd9d0f1091ad4c35e Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 23 Dec 2025 15:54:43 +0800 Subject: [PATCH 61/67] Revert "FROMLIST: riscv: dts: thead: lichee-pi-4a: enable HDMI" This reverts commit 419d3c15253bb368e0960fee7b13c60ac6d3399b. --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 3e99f905dc316e..4020c727f09e8e 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -28,17 +28,6 @@ chosen { stdout-path = "serial0:115200n8"; }; - - hdmi-connector { - compatible = "hdmi-connector"; - type = "a"; - - port { - hdmi_con_in: endpoint { - remote-endpoint = <&hdmi_out_con>; - }; - }; - }; }; &padctrl0_apsys { @@ -65,20 +54,6 @@ }; }; -&dpu { - status = "okay"; -}; - -&hdmi { - status = "okay"; -}; - -&hdmi_out_port { - hdmi_out_con: endpoint { - remote-endpoint = <&hdmi_con_in>; - }; -}; - &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; From abe8d39effc5ff6b820913cd0dc8ffa336b7a53b Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Thu, 16 Oct 2025 15:38:07 +0200 Subject: [PATCH 62/67] UPSTREAM: riscv: dts: thead: Add PWM fan and thermal control Add Device Tree nodes to enable a PWM controlled fan and it's associated thermal management for the Lichee Pi 4A board. This enables temperature-controlled active cooling for the Lichee Pi 4A board based on SoC temperature. Reviewed-by: Drew Fustini Tested-by: Drew Fustini Reviewed-by: Elle Rhumsaa Signed-off-by: Michal Wilczynski Signed-off-by: Drew Fustini (cherry picked from commit a9fb9c7e3bcd3107605e300680b95ad9615b3500) Signed-off-by: Han Gao --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 4020c727f09e8e..c58c2085ca92a3 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -28,9 +28,76 @@ chosen { stdout-path = "serial0:115200n8"; }; + + thermal-zones { + cpu-thermal { + polling-delay = <1000>; + polling-delay-passive = <1000>; + thermal-sensors = <&pvt 0>; + + trips { + fan_config0: fan-trip0 { + temperature = <39000>; + hysteresis = <5000>; + type = "active"; + }; + + fan_config1: fan-trip1 { + temperature = <50000>; + hysteresis = <5000>; + type = "active"; + }; + + fan_config2: fan-trip2 { + temperature = <60000>; + hysteresis = <5000>; + type = "active"; + }; + }; + + cooling-maps { + map-active-0 { + cooling-device = <&fan 1 1>; + trip = <&fan_config0>; + }; + + map-active-1 { + cooling-device = <&fan 2 2>; + trip = <&fan_config1>; + }; + + map-active-2 { + cooling-device = <&fan 3 3>; + trip = <&fan_config2>; + }; + }; + }; + }; + + fan: pwm-fan { + pinctrl-names = "default"; + pinctrl-0 = <&fan_pins>; + compatible = "pwm-fan"; + #cooling-cells = <2>; + pwms = <&pwm 1 10000000 0>; + cooling-levels = <0 66 196 255>; + }; + }; &padctrl0_apsys { + fan_pins: fan-0 { + pwm1-pins { + pins = "GPIO3_3"; /* PWM1 */ + function = "pwm"; + bias-disable; + drive-strength = <25>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + uart0_pins: uart0-0 { tx-pins { pins = "UART0_TXD"; From 971ece542ef5e0566a2b92d014383ae4de8c7cff Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 24 Nov 2025 18:52:24 +0800 Subject: [PATCH 63/67] FROMLIST: riscv: dts: thead: lichee-pi-4a: enable HDMI Lichee Pi 4A board features a HDMI Type-A connector connected to the HDMI TX controller of TH1520 SoC. Add a device tree node describing the connector, connect it to the HDMI controller, and enable everything on this display pipeline. Signed-off-by: Icenowy Zheng Link: https://lore.kernel.org/r/20251124105226.2860845-8-uwu@icenowy.me Signed-off-by: Han Gao --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index c58c2085ca92a3..e8971cafd1b1ce 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -83,6 +83,16 @@ cooling-levels = <0 66 196 255>; }; + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; }; &padctrl0_apsys { @@ -121,6 +131,20 @@ }; }; +&dpu { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_out_port { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; From 8641cd150582c5f72a08973a50b480f86070e6cf Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 13:51:56 +0800 Subject: [PATCH 64/67] XUANTIE: riscv: dts: thead: Add TH1520 USB nodes From: https://github.com/revyos/th1520-linux-kernel/commit/2bd78742752e4f0eb07b421c3b3fc662c953aff0 Signed-off-by: Jisheng Zhang Signed-off-by: Emil Renner Berthing Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 3263f4aa313cd0..41df5e297b450f 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -678,6 +678,29 @@ }; }; + misc_sysreg: misc_sysreg@ffec02c000 { + compatible = "thead,th1520-misc-sysreg", "syscon"; + reg = <0xff 0xec02c000 0x0 0x1000>; + }; + + usb: usb@ffec03f000 { + compatible = "thead,th1520-usb"; + reg = <0xff 0xec03f000 0x0 0x1000>; + thead,misc-sysreg = <&misc_sysreg>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + usb_dwc3: usb@ffe7040000 { + compatible = "snps,dwc3"; + reg = <0xff 0xe7040000 0x0 0x10000>; + interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; + dr_mode = "host"; + snps,usb3_lpm_capable; + status = "disabled"; + }; + }; + dmac0: dma-controller@ffefc00000 { compatible = "snps,axi-dma-1.01a"; reg = <0xff 0xefc00000 0x0 0x1000>; From a5aa314f194d101b621cd9acf02fa06c1c1fd729 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 13:50:07 +0800 Subject: [PATCH 65/67] XUANTIE: riscv: dts: thead: Add TH1520 I2C nodes From: https://github.com/revyos/th1520-linux-kernel/commit/ef4ac920a874b013f7609fb1f88fa08bcd445a01 Signed-off-by: Jisheng Zhang Signed-off-by: Emil Renner Berthing Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 41df5e297b450f..9e58cf7d45dcd1 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -458,6 +458,36 @@ status = "disabled"; }; + i2c0: i2c@ffe7f20000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xe7f20000 0x0 0x1000>; + clocks = <&clk CLK_I2C0>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@ffe7f24000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xe7f24000 0x0 0x1000>; + clocks = <&clk CLK_I2C1>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@ffe7f28000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xe7f28000 0x0 0x1000>; + clocks = <&clk CLK_I2C4>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + gpio@ffe7f34000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xe7f34000 0x0 0x1000>; @@ -556,6 +586,16 @@ thead,pad-group = <3>; }; + i2c2: i2c@ffec00c000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xec00c000 0x0 0x1000>; + clocks = <&clk CLK_I2C2>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + uart2: serial@ffec010000 { compatible = "snps,dw-apb-uart"; reg = <0xff 0xec010000 0x0 0x4000>; @@ -678,6 +718,16 @@ }; }; + i2c3: i2c@ffec014000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xec014000 0x0 0x1000>; + clocks = <&clk CLK_I2C3>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + misc_sysreg: misc_sysreg@ffec02c000 { compatible = "thead,th1520-misc-sysreg", "syscon"; reg = <0xff 0xec02c000 0x0 0x1000>; From 89a1d1cb32c3e6647631725470c49264e6c6accd Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Wed, 13 Dec 2023 01:58:00 +0100 Subject: [PATCH 66/67] XUANTIE: riscv: dts: thead: Add Lichee Pi 4A IO expansions From: https://github.com/revyos/th1520-linux-kernel/commit/b41720b46f4b203f7935d7cf5613c1782949774b Signed-off-by: Emil Renner Berthing Signed-off-by: Han Gao --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index e8971cafd1b1ce..77f44118375d83 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -95,6 +95,76 @@ }; }; +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + ioexp1: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "cam0_dvdd12", + "cam0_avdd28", + "cam0_dovdd18"; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + ioexp2: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "", + "cam0_reset", + "cam1_reset", + "cam2_reset", + "wl_host_wake", + "bt_resetn", + "", + "bt_host_wake"; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + ioexp3: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "tp0_rst", + "", + "", + "vcc5v_usb", + "vdd28_tp0", + "vdd33_lcd0", + "vdd18_lcd0", + "lcd0_reset"; + }; +}; + &padctrl0_apsys { fan_pins: fan-0 { pwm1-pins { @@ -108,6 +178,18 @@ }; }; + i2c3_pins: i2c3-0 { + i2c-pins { + pins = "I2C3_SCL", "I2C3_SDA"; + function = "i2c"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart0_pins: uart0-0 { tx-pins { pins = "UART0_TXD"; @@ -142,6 +224,33 @@ &hdmi_out_port { hdmi_out_con: endpoint { remote-endpoint = <&hdmi_con_in>; + + }; +}; + +&padctrl1_apsys { + i2c0_pins: i2c0-0 { + i2c-pins { + pins = "I2C0_SCL", "I2C0_SDA"; + function = "i2c"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + + i2c1_pins: i2c1-0 { + i2c-pins { + pins = "I2C1_SCL", "I2C1_SDA"; + function = "i2c"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; }; }; From cd9fadbed8e130e3128f2845107ba7e3a1d4a472 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 13:56:37 +0800 Subject: [PATCH 67/67] XUANTIE: riscv: dts: thead: Enable Lichee Pi 4A USB From: https://github.com/revyos/th1520-linux-kernel/commit/9f2a969ac4596062d55412ee6b7f25a6774b5358 Signed-off-by: Jisheng Zhang [esmil: fix gpio references] Signed-off-by: Emil Renner Berthing [ Han Gao: remove audio_i2c ] Signed-off-by: Han Gao --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 77f44118375d83..748ab9dea6991a 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -4,6 +4,7 @@ */ #include "th1520-lichee-module-4a.dtsi" +#include / { model = "Sipeed Lichee Pi 4A"; @@ -23,6 +24,11 @@ serial4 = &uart4; serial5 = &uart5; spi0 = &spi0; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; }; chosen { @@ -93,6 +99,26 @@ }; }; }; + + hub_5v: regulator-hub_5v { + compatible = "regulator-fixed"; + regulator-name = "HUB_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; + + vcc5v_usb: regulator-vcc5v_usb { + compatible = "regulator-fixed"; + regulator-name = "VCC5V_USB"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; }; &i2c0 {