diff --git a/Makefile b/Makefile index 2c4cc7609..0b8f3fce3 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SHELL = /bin/bash .SHELLFLAGS += -ex -KERNEL_VERSION ?= 6.12.41 +KERNEL_VERSION ?= 6.12.94 KERNEL_ABISUFFIX ?= +deb13 KERNEL_SUBVERSION ?= 1 KERNEL_FEATURESET ?= sonic diff --git a/patch/kconfig-exclusions b/patch/kconfig-exclusions deleted file mode 100644 index 756b4ab08..000000000 --- a/patch/kconfig-exclusions +++ /dev/null @@ -1,70 +0,0 @@ -[common] -# Unset STRICT_DEVMEM according to Broadcom's requirement and for CENTEC arm64 arch -CONFIG_STRICT_DEVMEM -# Unset classid and priority network cgroups due to conflict between cgroups v1 and v2 -CONFIG_CGROUP_NET_CLASSID -CONFIG_NET_CLS_CGROUP -CONFIG_NETFILTER_XT_MATCH_CGROUP -CONFIG_CGROUP_NET_PRIO -# Unset to enable UBIFS on flash -CONFIG_MTD_SPI_NOR_USE_4K_SECTORS -###-> mellanox_common-start -###-> mellanox_common-end -CONFIG_DRM -CONFIG_VIDEO_DEV -CONFIG_MEDIA_SUPPORT -CONFIG_MEDIA_CONTROLLER -CONFIG_DVB_CORE -CONFIG_MEDIA_TUNER -CONFIG_MEDIA_ATTACH - -[amd64] -CONFIG_AMD_MEM_ENCRYPT -# Unset X86_PAT according to Broadcom's requirement -CONFIG_X86_PAT -CONFIG_MLXSW_PCI -###-> mellanox_amd64-start -###-> mellanox_amd64-end - -[arm64] -CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU - -[marvell-prestera-arm64] -CONFIG_UBIFS_FS_ZSTD -CONFIG_CRYPTO_DEV_SAFEXCEL - -[pensando] -CONFIG_ARM64_VA_BITS_48 - -[armhf] - -[marvell-prestera-armhf] -CONFIG_ARCH_VIRT -CONFIG_ARCH_BCM -CONFIG_ARCH_EXYNOS -CONFIG_ARCH_HIGHBANK -CONFIG_ARCH_MXC -CONFIG_ARCH_MESON -CONFIG_ARCH_OMAP3 -CONFIG_ARCH_OMAP4 -CONFIG_SOC_OMAP5 -CONFIG_SOC_AM33XX -CONFIG_SOC_DRA7XX -CONFIG_ARCH_ROCKCHIP -CONFIG_ARCH_SOCFPGA -CONFIG_ARCH_SUNXI -CONFIG_ARCH_TEGRA -CONFIG_ARCH_VEXPRESS -CONFIG_ARCH_WM8850 -CONFIG_FW_CFG_SYSFS -CONFIG_VORTEX -CONFIG_NTP_PPS -CONFIG_SENSORS_MAX6620 -CONFIG_SND_LX6464ES -CONFIG_EFI -CONFIG_LOCK_DOWN_KERNEL -CONFIG_SECONDARY_TRUSTED_KEYRING -CONFIG_SYSTEM_BLACKLIST_KEYRING - -[mellanox-arm64] - diff --git a/patch/kconfig-force-inclusions b/patch/kconfig-force-inclusions deleted file mode 100644 index e14876637..000000000 --- a/patch/kconfig-force-inclusions +++ /dev/null @@ -1,3 +0,0 @@ -[arm64] -CONFIG_COMPAT_VDSO=y -CONFIG_THUMB2_COMPAT_VDSO=y diff --git a/patch/kconfig-inclusions b/patch/kconfig-inclusions deleted file mode 100644 index 11b64f57d..000000000 --- a/patch/kconfig-inclusions +++ /dev/null @@ -1,254 +0,0 @@ -[common] -CONFIG_LOG_BUF_SHIFT=20 -CONFIG_RTC_INTF_DEV_UIE_EMUL=y -###-> mellanox_common-start -###-> mellanox_common-end - -[amd64] -CONFIG_SATA_MOBILE_LPM_POLICY=1 -# For Arista -CONFIG_I2C_MUX_PCA9541=m -CONFIG_SENSORS_MAX6697=m -#CONFIG_SENSORS_DPS1900=m # TODO: enable once the DPS1900 patch is re-enabled -CONFIG_PCI_REASSIGN_PREF_MEM=y -# For cig-cs6436 -CONFIG_SERIAL_8250_LPSS=m -# SFF_8436 -CONFIG_EEPROM_SFF_8436=m -# For Dell S6000 -CONFIG_SENSORS_MAX6620=m -CONFIG_PMBUS=m -CONFIG_SENSORS_PMBUS=m -#CONFIG_SENSORS_DNI_DPS460=m # TODO: enable once the DPS460 patch is re-enabled -CONFIG_I2C_MUX_GPIO=m -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_SCH=m -# For Dell Z9100 -CONFIG_I2C_MUX_PCA954x=m -# For Ingrasys S9100 -CONFIG_I2C_GPIO=m -CONFIG_GPIO_PCA953X=m -# For Inventec d7032 -CONFIG_GPIO_ICH=m -# For mitac ly1200 -CONFIG_SENSORS_MAX31790=m -# For optoe -CONFIG_EEPROM_OPTOE=m -###-> mellanox_amd64-start -CONFIG_X86_AMD_PLATFORM_DEVICE=y -CONFIG_MCTP=y -CONFIG_DMI_SYSFS=y -CONFIG_OF=y -CONFIG_EEPROM_AT24=m -CONFIG_AMD_XGBE=m -CONFIG_IGB=m -CONFIG_MLXSW_CORE=m -CONFIG_MARVELL_PHY=m -CONFIG_MARVELL_10G_PHY=m -CONFIG_SERIAL_8250_DW=y -CONFIG_HW_RANDOM_AMD=m -CONFIG_I2C_CHARDEV=m -CONFIG_I2C_MUX=m -CONFIG_I2C_SMBUS=m -CONFIG_I2C_I801=m -CONFIG_I2C_DESIGNWARE_PCI=m -CONFIG_I2C_MLXCPLD=m -CONFIG_I2C_SLAVE=y -CONFIG_PINCTRL=y -CONFIG_GPIOLIB=y -CONFIG_SENSORS_K10TEMP=m -CONFIG_SENSORS_DRIVETEMP=m -CONFIG_SENSORS_CORETEMP=m -CONFIG_SENSORS_JC42=m -CONFIG_SENSORS_POWR1220=m -CONFIG_SENSORS_LM75=m -CONFIG_SENSORS_EMC1403=m -CONFIG_SENSORS_EMC2305=m -CONFIG_SENSORS_STTS751=m -CONFIG_SENSORS_TMP102=m -CONFIG_SENSORS_TMP421=m -CONFIG_THERMAL_NETLINK=y -CONFIG_INTEL_PCH_THERMAL=m -CONFIG_WATCHDOG_SYSFS=y -CONFIG_LPC_ICH=m -CONFIG_MFD_INTEL_LPSS_PCI=y -CONFIG_LEDS_MLXREG=m -CONFIG_LEDS_TRIGGER_TIMER=m -CONFIG_DW_DMAC_PCI=y -CONFIG_MELLANOX_PLATFORM=y -CONFIG_MLX_PLATFORM=m -CONFIG_NET_DEVLINK=y -CONFIG_I2C_MUX_REG=m -CONFIG_I2C_MUX_MLXCPLD=m -CONFIG_REGMAP_I2C=m -CONFIG_IIO_SYSFS_TRIGGER=m -CONFIG_NVME_HWMON=y -CONFIG_MLXSW_CORE_HWMON=y -CONFIG_MLXSW_I2C=m -CONFIG_MLXSW_MINIMAL=m -CONFIG_MLXSW_CORE_THERMAL=n -CONFIG_MLXREG_HOTPLUG=m -CONFIG_MLXREG_IO=m -CONFIG_MLX_WDT=m -CONFIG_MLXREG_LC=m -#CONFIG_MLXREG_DPU=m -CONFIG_SENSORS_MLXREG_FAN=m -CONFIG_GPIO_GENERIC=m -CONFIG_MAX1363=m -CONFIG_SENSORS_TPS53679=m -CONFIG_SENSORS_XDPE122=m -CONFIG_SENSORS_MP2975=m -#CONFIG_SENSORS_MP2855=m -CONFIG_SENSORS_MP2888=m -CONFIG_SENSORS_MP2891=m -CONFIG_CPU_THERMAL=y -CONFIG_IGB_HWMON=y -CONFIG_MFD_CORE=y -CONFIG_MFD_INTEL_LPSS=y -CONFIG_TI_ADS1015=m -CONFIG_PINCTRL_INTEL=y -CONFIG_PINCTRL_CANNONLAKE=m -CONFIG_PINCTRL_DENVERTON=m -CONFIG_NVSW_SN2201=m -CONFIG_I2C_DESIGNWARE_PLATFORM=m -CONFIG_I2C_DESIGNWARE_BAYTRAIL=y -CONFIG_I2C_DESIGNWARE_CORE=m -CONFIG_SPI_PXA2XX=m -CONFIG_SENSORS_XDPE152=m -CONFIG_SENSORS_IIO_HWMON=m -CONFIG_SENSORS_LM25066=m -CONFIG_SENSORS_UCD9000=m -CONFIG_SENSORS_UCD9200=m -CONFIG_THERMAL_OF=y -CONFIG_MCTP_FLOWS=y -CONFIG_MCTP_TRANSPORT_I2C=m -CONFIG_I2C_SLAVE_EEPROM=m -#CONFIG_I2C_ASF=m -CONFIG_SPI_AMD=m -CONFIG_PINCTRL_AMD=y -CONFIG_EDAC_AMD64=m -CONFIG_AMD_XGBE_DCB=y -CONFIG_SENSORS_ISL68137=m -###-> mellanox_amd64-end -# For Cisco 8000 -CONFIG_PHYLIB=m -CONFIG_OF_GPIO=y -CONFIG_OF_MDIO=m -CONFIG_MDIO_BUS_MUX_GPIO=m -CONFIG_MDIO_BUS_MUX=m -CONFIG_REGMAP_MMIO=y -CONFIG_TI_TLC4541=m -CONFIG_SENSORS_LTC2978=m -CONFIG_SENSORS_LTC2945=m -CONFIG_SENSORS_TPS40422=m -CONFIG_SENSORS_ADM1275=m -CONFIG_SPI_INTEL_PLATFORM=m -CONFIG_SPI_INTEL=m -# For pensando -CONFIG_IONIC=m -# For AMD Ryzen Embedded processors -CONFIG_PCI_ENDPOINT=y -CONFIG_PCIE_DW=y -CONFIG_PCIE_DW_HOST=y -CONFIG_PCIE_DW_EP=y -CONFIG_PCIE_DW_PLAT=y -CONFIG_PCIE_DW_PLAT_HOST=y -CONFIG_PCIE_DW_PLAT_EP=y -# For Micas -CONFIG_MDIO_BITBANG=m -CONFIG_MDIO_GPIO=m -CONFIG_SPI_GPIO=m -CONFIG_SENSORS_INA3221=m -# For Nokia -CONFIG_RTC_DRV_DS1307=m -CONFIG_SENSORS_TMP464=m -CONFIG_RTC_DRV_PCF85363=m -# For Nexthop -CONFIG_PCI_STUB=y -CONFIG_SENSORS_ADM1266=m - -[arm64] -# For enabling SDEI -CONFIG_ARM_SDE_INTERFACE=y -# For Marvell -CONFIG_EEPROM_SFF_8436=m -CONFIG_EEPROM_OPTOE=m -CONFIG_I2C_MUX_GPIO=m -CONFIG_MTD_RAW_NAND=m -CONFIG_MTD_NAND_ECC_SW_BCH=y -CONFIG_MTD_NAND_MARVELL=m -CONFIG_SENSORS_EMC2305=m -CONFIG_PHY_MVEBU_CP110_COMPHY=y -CONFIG_SPI_ORION=m -CONFIG_ARM_SMC_WATCHDOG=m -# For pensando -CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_EMBEDDED=y -CONFIG_GENERIC_IRQ_DEBUGFS=y -CONFIG_GPIO_DWAPB=m -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IRQSOFF_TRACER=y -CONFIG_KALLSYMS_ALL=y -CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y -CONFIG_SCHED_TRACER=y -CONFIG_MEMTEST=y -CONFIG_MMC_DEBUG=y -CONFIG_MMC_SDHCI_CADENCE=m -CONFIG_PMBUS=m -CONFIG_SENSORS_PMBUS=m -CONFIG_SENSORS_LTC2978=m -CONFIG_SENSORS_TPS53679=m -CONFIG_RTC_DRV_PCF85363=m -CONFIG_RTC_CLASS=y -CONFIG_SPI_CADENCE_QUADSPI=m -CONFIG_SPI_DESIGNWARE=m -CONFIG_SPI_DW_MMIO=m -CONFIG_SQUASHFS_DECOMP_MULTI=y -CONFIG_PREEMPTIRQ_TRACEPOINTS=y -CONFIG_RING_BUFFER_ALLOW_SWAP=y -CONFIG_KEXEC_FILE=y - -[marvell-prestera-arm64] - -[pensando] -CONFIG_ARCH_PENSANDO=y -CONFIG_ARCH_PENSANDO_ELBA_SOC=y -CONFIG_PENSANDO_SOC_PENFW=y -CONFIG_EDAC_ELBA=y -CONFIG_IRQ_PENSANDO=y -CONFIG_MFD_PENSANDO_ELBASR=y -CONFIG_RESET_ELBASR=y -CONFIG_UIO_PCIEMAC=m -CONFIG_UIO_PENMSI1=m -CONFIG_UIO_PENGIC=m -CONFIG_UIO_PENMSI=m -CONFIG_ARM64_VA_BITS_39=y -CONFIG_COMMON_CLK_CS2000_CP=y -CONFIG_I2C_RD1173=y -CONFIG_CONTEXT_TRACKING=y -CONFIG_NO_HZ_FULL=y -CONFIG_RCU_NOCB_CPU=y -CONFIG_VIRT_CPU_ACCOUNTING=y -CONFIG_VIRT_CPU_ACCOUNTING_GEN=y -CONFIG_RTC_DRV_ELBA_CPLD=y - -[armhf] -CONFIG_EEPROM_SFF_8436=m -CONFIG_EEPROM_OPTOE=m -CONFIG_I2C_MUX_GPIO=m - -[marvell-prestera-armhf] -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y - -[nvidia-bluefield] -CONFIG_MMC_DW=y -CONFIG_MMC_DW_PLTFM=y -CONFIG_MMC_DW_BLUEFIELD=y -CONFIG_EFIVAR_FS=y - -[mellanox-arm64] - diff --git a/patch/kconfig-secure-boot-exclusions b/patch/kconfig-secure-boot-exclusions deleted file mode 100644 index 68fb8c58f..000000000 --- a/patch/kconfig-secure-boot-exclusions +++ /dev/null @@ -1,20 +0,0 @@ -[common] - -[amd64] -CONFIG_MODULE_SIG_SHA256 -# For mellanox -CONFIG_SECURITY_LOCKDOWN_LSM -CONFIG_SECURITY_LOCKDOWN_LSM_EARLY -CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE -CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT - -[arm64] -CONFIG_MODULE_SIG_SHA256 -# For mellanox -CONFIG_SECURITY_LOCKDOWN_LSM -CONFIG_SECURITY_LOCKDOWN_LSM_EARLY -CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE -CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT - -[armhf] - diff --git a/patch/kconfig-secure-boot-inclusions b/patch/kconfig-secure-boot-inclusions deleted file mode 100644 index cfd9e900c..000000000 --- a/patch/kconfig-secure-boot-inclusions +++ /dev/null @@ -1,18 +0,0 @@ -[common] - -[amd64] -CONFIG_SYSTEM_TRUSTED_KEYS="debian/certs/debian-uefi-certs.pem" -CONFIG_MODULE_SIG_HASH="sha512" -CONFIG_MODULE_SIG_SHA512=y -CONFIG_KEXEC_SIG_FORCE=y -CONFIG_MODULE_SIG_FORCE=y - -[arm64] -CONFIG_SYSTEM_TRUSTED_KEYS="debian/certs/debian-uefi-certs.pem" -CONFIG_MODULE_SIG_HASH="sha512" -CONFIG_MODULE_SIG_SHA512=y -CONFIG_KEXEC_SIG=y -CONFIG_MODULE_SIG_FORCE=y - -[armhf] - diff --git a/patches-sonic/0001-Add-device-tree-for-Nokia-BMC-H6-128-platform.patch b/patches-sonic/0001-Add-device-tree-for-Nokia-BMC-H6-128-platform.patch index b110b9e23..e453e3b8c 100644 --- a/patches-sonic/0001-Add-device-tree-for-Nokia-BMC-H6-128-platform.patch +++ b/patches-sonic/0001-Add-device-tree-for-Nokia-BMC-H6-128-platform.patch @@ -28,9 +28,9 @@ index 3e904b273f1f..5caf80a7ff69 100644 ast2700-evb.dtb \ nexthop-b27-r0.dtb \ + nokia-ast2700-h6-128-r0.dtb \ + ast2700-evb_ast1700-evb.dtb \ + ast2700-evb_ast1700-evb-dual.dtb \ ast2700-raw.dtb \ - ast2700-evb-s0.dtb \ - ast2700-evb-s1.dtb \ diff --git a/arch/arm64/boot/dts/aspeed/nokia-ast2700-h6-128-r0.dts b/arch/arm64/boot/dts/aspeed/nokia-ast2700-h6-128-r0.dts new file mode 100644 index 000000000000..79b5bd7fb94a diff --git a/patches-sonic/0001-aspeed-ast2700-support.patch b/patches-sonic/0001-aspeed-ast2700-support.patch index 876353830..c180aa7a7 100644 --- a/patches-sonic/0001-aspeed-ast2700-support.patch +++ b/patches-sonic/0001-aspeed-ast2700-support.patch @@ -1,50 +1,23 @@ -From: Chander -Date: Tue, 23 Dec 2025 10:16:25 +0000 -Subject: [PATCH] Add Aspeed AST2700 support +From: Chandrasekaran Swaminathan +Date: Wed, 09 Sep 2026 15:51:49 +0000 +Subject: [PATCH] Aspeed AST2700 support: Aspeed-namespace files (new and updated) -This patch adds support for Aspeed AST2700 ARM64 SoC including: -- Device tree files for AST2700 and related boards -- Aspeed-specific drivers (pinctrl, clk, soc, crypto, etc.) -- Faraday ethernet driver support -- Kconfig and Makefile updates +All files under the Aspeed namespace (new files plus updates to +Aspeed drivers already present upstream), from a fresh Aspeed +merge at v00.07.04 on the 6.12.94 SONiC kernel. -Signed-off-by: Chander +Signed-off-by: Chandrasekaran Swaminathan --- -diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms ---- a/arch/arm64/Kconfig.platforms 2025-08-01 08:48:47.000000000 +0000 -+++ b/arch/arm64/Kconfig.platforms 2025-12-23 10:16:21.331029200 +0000 -@@ -40,6 +40,12 @@ - This enables support for Apple's in-house ARM SoC family, starting - with the Apple M1. - -+config ARCH_ASPEED -+ bool "Aspeed SoC family" -+ help -+ Say yes if you intend to run on an Aspeed ast2700 or similar -+ seventh generation Aspeed BMCs. -+ - menuconfig ARCH_BCM - bool "Broadcom SoC Support" - -diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile ---- a/arch/arm64/boot/dts/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/arch/arm64/boot/dts/Makefile 2025-12-23 10:16:21.337029100 +0000 -@@ -9,6 +9,7 @@ - subdir-y += apm - subdir-y += apple - subdir-y += arm -+subdir-y += aspeed - subdir-y += bitmain - subdir-y += broadcom - subdir-y += cavium diff --git a/arch/arm64/boot/dts/aspeed/Makefile b/arch/arm64/boot/dts/aspeed/Makefile --- a/arch/arm64/boot/dts/aspeed/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/Makefile 2025-12-23 10:16:06.861271783 +0000 -@@ -0,0 +1,16 @@ ++++ b/arch/arm64/boot/dts/aspeed/Makefile 2026-09-09 15:51:27.102504264 +0000 +@@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0 + +dtb-$(CONFIG_ARCH_ASPEED) += \ + ast2700-evb.dtb \ ++ ast2700-evb_ast1700-evb.dtb \ ++ ast2700-evb_ast1700-evb-dual.dtb \ + ast2700-raw.dtb \ + ast2700-evb-s0.dtb \ + ast2700-evb-s1.dtb \ @@ -56,10 +29,21 @@ diff --git a/arch/arm64/boot/dts/aspeed/Makefile b/arch/arm64/boot/dts/aspeed/Ma + ast2700-evb-256-abr.dtb \ + ast2700-slt.dtb \ + ast2700-fpga.dtb \ -+ ast2700-ci-host.dtb ++ ast2700-ci-host.dtb \ ++ ast2700a1-evb.dtb \ ++ ast2700a1-raw.dtb \ ++ ast2700a1-ncsi.dtb \ ++ ast2700a1-dcscm.dtb \ ++ ast2700a1-dcscm_ast1700a1-evb.dtb \ ++ ast2700a1-dcscm_ast1700a1-evb-dual.dtb \ ++ ast2700a1-dcscm_ast1800-evb.dtb \ ++ ast2700a1-evb-256-abr.dtb \ ++ ast2700a1-evb-s0.dtb \ ++ ast2700a1-evb-s1.dtb \ ++ ast2700a1-ci-host.dtb diff --git a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi 2025-12-23 10:16:06.861271783 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi 2026-09-09 15:51:27.102504264 +0000 @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0+ + @@ -95,7 +79,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi b/arch/ +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi 2025-12-23 10:16:06.861271783 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi 2026-09-09 15:51:27.102504264 +0000 @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ + @@ -156,8 +140,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi b/a +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi 2025-12-23 10:16:06.861271783 +0000 -@@ -0,0 +1,1425 @@ ++++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi 2026-09-09 15:51:27.102504264 +0000 +@@ -0,0 +1,1435 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2025 ASPEED Corp. + @@ -684,6 +668,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi b/arch/arm64/boot + groups = "JTAGM1"; + }; + ++ pinctrl_jtagm1trst_default: jtagm1trst-default { ++ function = "JTAGM1"; ++ groups = "JTAGM1TRST"; ++ }; ++ + pinctrl_mdio0_default: mdio0-default { + function = "MDIO0"; + groups = "MDIO0"; @@ -1219,6 +1208,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi b/arch/arm64/boot + groups = "CANBUS"; + }; + ++ pinctrl_canstby_default: canstby-default { ++ function = "CANBUS"; ++ groups = "CANBUSSTBY"; ++ }; ++ + pinctrl_di2c0_default: di2c0-default { + function = "I2C0"; + groups = "DI2C0"; @@ -1585,8 +1579,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi b/arch/arm64/boot +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,2870 @@ ++++ b/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi 2026-09-09 15:51:27.102504264 +0000 +@@ -0,0 +1,2867 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include @@ -1817,8 +1811,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + uphy3a: usb-phy3@12010000 { -+ compatible = "aspeed,ast2700-uphy3a"; -+ reg = <0x0 0x12010000 0x0 0xBC>; ++ compatible = "aspeed,ast2700-usb3-phy"; ++ reg = <0x0 0x12010000 0x0 0xC0>; + clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>; + resets = <&syscon0 SCU0_RESET_PORTA_PHY3>; + aspeed,scu = <&syscon0>; @@ -1827,7 +1821,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + vhuba1: usb-vhub@12011000 { -+ compatible = "aspeed,ast2700-usb-vhuba1"; ++ compatible = "aspeed,ast2700-usb-vhub"; + reg = <0x0 0x12011000 0x0 0x820>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>; @@ -1836,8 +1830,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + aspeed,vhub-generic-endpoints = <21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2axhpd1_default>; -+ aspeed,device = <&pcie_cfg0>; -+ aspeed,scu = <&syscon0>; ++ aspeed,enlarge-fifo; + status = "disabled"; + }; + @@ -1850,8 +1843,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + uphy3b: usb-phy3@12020000 { -+ compatible = "aspeed,ast2700-uphy3b"; -+ reg = <0x0 0x12020000 0x0 0xBC>; ++ compatible = "aspeed,ast2700-usb3-phy"; ++ reg = <0x0 0x12020000 0x0 0xC0>; + clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>; + resets = <&syscon0 SCU0_RESET_PORTB_PHY3>; + aspeed,scu = <&syscon0>; @@ -1860,7 +1853,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + vhubb1: usb-vhub@12021000 { -+ compatible = "aspeed,ast2700-usb-vhubb1"; ++ compatible = "aspeed,ast2700-usb-vhub"; + reg = <0x0 0x12021000 0x0 0x820>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>; @@ -1869,8 +1862,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + aspeed,vhub-generic-endpoints = <21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2bxhpd1_default>; -+ aspeed,device = <&pcie_cfg1>; -+ aspeed,scu = <&syscon0>; ++ aspeed,enlarge-fifo; + status = "disabled"; + }; + @@ -1900,7 +1892,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + usb3ahp: usb3ahp { -+ compatible = "aspeed,ast2700-usb3ahp"; ++ compatible = "aspeed,ast2700-usb3hp"; + clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>; + resets = <&syscon0 SCU0_RESET_PORTA_XHCI>; + pinctrl-names = "default"; @@ -1939,7 +1931,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + usb3bhp: usb3bhp { -+ compatible = "aspeed,ast2700-usb3bhp"; ++ compatible = "aspeed,ast2700-usb3hp"; + clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>; + resets = <&syscon0 SCU0_RESET_PORTB_XHCI>; + pinctrl-names = "default"; @@ -1951,7 +1943,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + vhuba0: usb-vhub@12060000 { -+ compatible = "aspeed,ast2700-usb-vhuba0"; ++ compatible = "aspeed,ast2700-usb-vhub"; + reg = <0x0 0x12060000 0x0 0x820>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>; @@ -1960,8 +1952,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + aspeed,vhub-generic-endpoints = <21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2ad0_default>; -+ aspeed,device = <&pcie_cfg0>; -+ aspeed,scu = <&syscon0>; ++ aspeed,txfifo-retry-quirk; + status = "disabled"; + }; + @@ -1977,18 +1968,16 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + usb2ahp: usb2ahp { -+ compatible = "aspeed,ast2700-usb2ahp"; ++ compatible = "aspeed,ast2700-usb2hp"; + reg = <0x0 0x12061800 0x0 0x90>; + clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>; + resets = <&syscon0 SCU0_RESET_PORTA_VHUB_EHCI>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_usb2ahp_default>; + aspeed,device = <&pcie_cfg0>; + status = "disabled"; + }; + + vhubb0: usb-vhub@12062000 { -+ compatible = "aspeed,ast2700-usb-vhubb0"; ++ compatible = "aspeed,ast2700-usb-vhub"; + reg = <0x0 0x12062000 0x0 0x820>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>; @@ -1997,8 +1986,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + aspeed,vhub-generic-endpoints = <21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2bd0_default>; -+ aspeed,device = <&pcie_cfg1>; -+ aspeed,scu = <&syscon0>; ++ aspeed,txfifo-retry-quirk; + status = "disabled"; + }; + @@ -2014,19 +2002,17 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + usb2bhp: usb2bhp { -+ compatible = "aspeed,ast2700-usb2bhp"; ++ compatible = "aspeed,ast2700-usb2hp"; + reg = <0x0 0x12063800 0x0 0x90>; + clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>; + resets = <&syscon0 SCU0_RESET_PORTB_VHUB_EHCI>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_usb2bhp_default>; + aspeed,device = <&pcie_cfg1>; + status = "disabled"; + }; + + hace: crypto@12070000 { + compatible = "aspeed,ast2700-hace"; -+ reg = <0x0 0x12070000 0x0 0x200>; ++ reg = <0x0 0x12070000 0x0 0x200>, <0x0 0x12c1f000 0x0 0x10>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_GATE_HACCLK>; + resets = <&syscon0 SCU0_RESET_HACE>; @@ -2107,9 +2093,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + status = "disabled"; + }; + -+ rvas1: rvas@120bc000 { ++ rvas1: rvas@121b8000 { + compatible = "aspeed,ast2700-rvas"; -+ reg = <0x0 0x120bc000 0x0 0x800>, ++ reg = <0x0 0x121b8000 0x0 0x800>, + <0x0 0x12c14800 0x0 0x800>, + <0x0 0x120a1000 0x0 0x1000>; + clocks = <&syscon0 SCU0_CLK_GATE_RVAS1CLK>, @@ -2129,8 +2115,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; -+ ranges = <0x01000000 0x0 0x00000000 0x0 0x00000000 0x0 0x00008000>, /* I/O */ -+ <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; /* memory */ ++ ranges = <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; + interrupts = ; + resets = <&syscon0 SCU0_RESET_H2X0>, + <&syscon0 SCU0_RESET_PCIE0RST>; @@ -2167,8 +2152,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; -+ ranges = <0x01000000 0 0x00000000 0x0 0x00000000 0x0 0x00008000>, -+ <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x20000000>; /* memory */ ++ ranges = <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x20000000>; + interrupts = ; + resets = <&syscon0 SCU0_RESET_H2X1>, + <&syscon0 SCU0_RESET_PCIE1RST>; @@ -2285,18 +2269,18 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + scu_ic0: interrupt-controller@1D0 { -+ #interrupt-cells = <1>; + compatible = "aspeed,ast2700-scu-ic0"; + reg = <0x1d0 0xc>; + interrupts = ; ++ #interrupt-cells = <1>; + interrupt-controller; + }; + + scu_ic1: interrupt-controller@1E0 { -+ #interrupt-cells = <1>; + compatible = "aspeed,ast2700-scu-ic1"; + reg = <0x1e0 0xc>; + interrupts = ; ++ #interrupt-cells = <1>; + interrupt-controller; + }; + @@ -2378,6 +2362,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + clocks = <&syscon0 SCU0_CLK_GATE_CRT0CLK>; + resets = <&syscon0 SCU0_RESET_CRT0>; + syscon = <&syscon0>; ++ syscon_io = <&syscon1>; + status = "disabled"; + interrupts-extended = <&gic GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, + <&scu_ic0 ASPEED_AST2700_SCU_IC0_PCIE_PERST_LO_TO_HI>, @@ -2424,6 +2409,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pcie_vuart0: serial@12c18000 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x12c18000 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; @@ -2433,6 +2420,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pcie_vuart1: serial@12c18100 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x12c18100 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; @@ -2442,6 +2431,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pcie_vuart2: serial@12c18200 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x12c18200 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; @@ -2451,6 +2442,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pcie_vuart3: serial@12c18300 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x12c18300 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts = ; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; @@ -2632,18 +2625,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + #size-cells = <2>; + aspeed,device = <&pcie_cfg0>; + -+ e2m_ic0: interrupt-controller@14 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2700-e2m-ic"; -+ reg = <0 0x14 0 0x8>; -+ interrupts-extended = <&gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "e2m"; -+ interrupt-controller; -+ }; -+ + pcie0_mmbi0: pcie0-mmbi@0 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic0 ASPEED_AST2700_E2M_MMBI_H2B_INT0>; + index = <0>; + pid = <3>; + bar = <0x3c>; @@ -2653,7 +2636,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + pcie0_mmbi1: pcie0-mmbi@1 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic0 ASPEED_AST2700_E2M_MMBI_H2B_INT1>; + index = <1>; + pid = <4>; + bar = <0x4c>; @@ -2663,7 +2645,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + pcie0_mmbi2: pcie0-mmbi@2 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic0 ASPEED_AST2700_E2M_MMBI_H2B_INT2>; + index = <2>; + pid = <5>; + bar = <0x5c>; @@ -2673,7 +2654,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + pcie0_mmbi3: pcie0-mmbi@3 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic0 ASPEED_AST2700_E2M_MMBI_H2B_INT3>; + index = <3>; + pid = <6>; + bar = <0x6c>; @@ -2690,17 +2670,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + #size-cells = <2>; + aspeed,device = <&pcie_cfg1>; + -+ e2m_ic1: interrupt-controller@14 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2700-e2m-ic"; -+ reg = <0 0x14 0 0x8>; -+ interrupts-extended = <&gic GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-controller; -+ }; -+ + pcie1_mmbi4: pcie1-mmbi@4 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic1 ASPEED_AST2700_E2M_MMBI_H2B_INT4>; + index = <4>; + pid = <11>; + bar = <0x3c>; @@ -2710,7 +2681,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + pcie1_mmbi5: pcie1-mmbi@5 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic1 ASPEED_AST2700_E2M_MMBI_H2B_INT5>; + index = <5>; + pid = <12>; + bar = <0x4c>; @@ -2720,7 +2690,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + pcie1_mmbi6: pcie1-mmbi@6 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic1 ASPEED_AST2700_E2M_MMBI_H2B_INT6>; + index = <6>; + pid = <13>; + bar = <0x5c>; @@ -2730,7 +2699,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + pcie1_mmbi7: pcie1-mmbi@7 { + compatible = "aspeed,ast2700-pcie-mmbi"; -+ interrupts-extended = <&e2m_ic1 ASPEED_AST2700_E2M_MMBI_H2B_INT7>; + index = <7>; + pid = <14>; + bar = <0x6c>; @@ -2884,18 +2852,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + status = "disabled"; + }; + -+ sgmii: phy@14C01000 { -+ compatible = "aspeed,ast2700-sgmii"; -+ reg = <0x0 0x14c01000 0x0 0x40>; -+ -+ aspeed,plda = <&pcie_phy2>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_sgmii_default>; -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ + mac0: ethernet@14050000 { + compatible = "aspeed,ast2700-mac", "faraday,ftgmac100"; + reg = <0x0 0x14050000 0x0 0x200>; @@ -2968,8 +2924,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; -+ ranges = <0x01000000 0 0x00000000 0x0 0x00000000 0x0 0x00008000>, -+ <0x02000000 0 0xa0000000 0x0 0xa0000000 0x0 0x20000000>; /* memory */ ++ ranges = <0x02000000 0 0xa0000000 0x0 0xa0000000 0x0 0x20000000>; + interrupts-extended = <&intc1_4 31>; + resets = <&syscon1 SCU1_RESET_H2X>, + <&syscon1 SCU1_RESET_PCIE2RST>; @@ -3009,7 +2964,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + vhubc: usb-vhub@14120000 { -+ compatible = "aspeed,ast2700-usb-vhubc"; ++ compatible = "aspeed,ast2700-usb-vhub"; + reg = <0x0 0x14120000 0x0 0x820>; + interrupts-extended = <&intc1_4 28>; + clocks = <&syscon1 SCU1_CLK_GATE_PORTCUSB2CLK>; @@ -3033,7 +2988,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + }; + + vhubd: usb-vhub@14122000 { -+ compatible = "aspeed,ast2700-usb-vhubd"; ++ compatible = "aspeed,ast2700-usb-vhub"; + reg = <0x0 0x14122000 0x0 0x820>; + interrupts-extended = <&intc1_4 29>; + clocks = <&syscon1 SCU1_CLK_GATE_PORTDUSB2CLK>; @@ -3092,6 +3047,19 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + status = "disabled"; + }; + ++ sgmii: phy@14c01000 { ++ compatible = "aspeed,ast2700-sgmii"; ++ reg = <0x0 0x14c01000 0x0 0x40>; ++ ++ phys = <&pcie_phy2>; ++ aspeed,scu = <&syscon1>; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sgmii_default>; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ + syscon1: syscon@14c02000 { + compatible = "aspeed,ast2700-scu1", "syscon", "simple-mfd"; + reg = <0x0 0x14c02000 0x0 0x1000>; @@ -3101,19 +3069,24 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + #clock-cells = <1>; + #reset-cells = <1>; + ++ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, ++ <&syscon1 SCU1_CLK_RGMII>, ++ <&syscon1 SCU1_CLK_RMII>; ++ assigned-clock-rates = <200000000>, <125000000>, <50000000>; ++ + scu_ic2: interrupt-controller@100 { -+ #interrupt-cells = <1>; + compatible = "aspeed,ast2700-scu-ic2"; + reg = <0x100 0x8>; + interrupts-extended = <&intc1_5 0>; ++ #interrupt-cells = <1>; + interrupt-controller; + }; + + scu_ic3: interrupt-controller@108 { -+ #interrupt-cells = <1>; + compatible = "aspeed,ast2700-scu-ic3"; + reg = <0x108 0x8>; + interrupts-extended = <&intc1_5 26>; ++ #interrupt-cells = <1>; + interrupt-controller; + }; + @@ -3189,7 +3162,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + interrupts-extended = <&intc1_0 10>, <&intc1_0 16>; + clocks = <&syscon1 SCU1_CLK_GATE_ESPI0CLK>; + resets = <&syscon1 SCU1_RESET_ESPI0>; -+ syscon = <&syscon1>; ++ aspeed,syscon = <&syscon1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_espi0_default>; + status = "disabled"; @@ -3201,7 +3174,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + interrupts-extended = <&intc1_1 10>, <&intc1_1 16>; + clocks = <&syscon1 SCU1_CLK_GATE_ESPI1CLK>; + resets = <&syscon1 SCU1_RESET_ESPI1>; -+ syscon = <&syscon1>; ++ aspeed,syscon = <&syscon1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_espi1_default>; + status = "disabled"; @@ -3223,7 +3196,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + clocks = <&syscon1 SCU1_CLK_AHB>; + resets = <&syscon1 SCU1_RESET_JTAG1>; + pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_jtagm1_default>; ++ pinctrl-0 = <&pinctrl_jtagm1_default &pinctrl_jtagm1trst_default>; + status = "disabled"; + }; + @@ -3367,6 +3340,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pcie_phy2: phy@14c1c000 { + compatible = "aspeed,ast2700-pcie-phy", "syscon"; + reg = <0x0 0x14c1c000 0x0 0x800>; ++ #phy-cells = <0>; + }; + + e2m_config2: e2m-config@14c1d000 { @@ -3453,7 +3427,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + compatible = "aspeed,ast2600-peci"; + reg = <0x0 0x14c1f000 0x0 0x100>; + interrupts-extended = <&intc1_5 4>; -+ clocks = <&syscon1 SCU1_CLK_GATE_IPEREFCLK>; ++ clocks = <&syscon1 SCU1_CLK_PECI>; + resets = <&syscon1 SCU1_RESET_PECI>; + cmd-timeout-ms = <1000>; + clock-frequency = <1000000>; @@ -3671,36 +3645,48 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + vuart0: serial@14c30000 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x14c30000 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts-extended = <&intc1_0 17>; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; ++ dma-channel = <12>; + status = "disabled"; + }; + + vuart1: serial@14c30100 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x14c30100 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts-extended = <&intc1_0 18>; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; ++ dma-channel = <13>; + status = "disabled"; + }; + + vuart2: serial@14c30200 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x14c30200 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts-extended = <&intc1_1 17>; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; ++ dma-channel = <14>; + status = "disabled"; + }; + + vuart3: serial@14c30300 { + compatible = "aspeed,ast2700-uart"; + reg = <0x0 0x14c30300 0x0 0x40>; ++ reg-shift = <2>; ++ reg-io-width = <4>; + interrupts-extended = <&intc1_1 18>; + clocks = <&syscon0 SCU0_CLK_APB>; + virtual; ++ dma-channel = <15>; + status = "disabled"; + }; + @@ -3871,6 +3857,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd0_default &pinctrl_rxd0_default>; ++ dma-channel = <0>; + status = "disabled"; + }; + @@ -3885,6 +3872,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>; ++ dma-channel = <1>; + status = "disabled"; + }; + @@ -3899,6 +3887,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>; ++ dma-channel = <2>; + status = "disabled"; + }; + @@ -3913,6 +3902,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd3_default &pinctrl_rxd3_default>; ++ dma-channel = <3>; + status = "disabled"; + }; + @@ -3927,6 +3917,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd5_default &pinctrl_rxd5_default>; ++ dma-channel = <4>; + status = "disabled"; + }; + @@ -3941,6 +3932,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd6_default &pinctrl_rxd6_default>; ++ dma-channel = <5>; + status = "disabled"; + }; + @@ -3955,6 +3947,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd7_default &pinctrl_rxd7_default>; ++ dma-channel = <6>; + status = "disabled"; + }; + @@ -3969,6 +3962,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd8_default &pinctrl_rxd8_default>; ++ dma-channel = <7>; + status = "disabled"; + }; + @@ -3982,6 +3976,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd9_default &pinctrl_rxd9_default>; ++ dma-channel = <8>; + status = "disabled"; + }; + @@ -3995,6 +3990,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd10_default &pinctrl_rxd10_default>; ++ dma-channel = <9>; + status = "disabled"; + }; + @@ -4008,6 +4004,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + no-loopback-test; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd11_default &pinctrl_rxd11_default>; ++ dma-channel = <10>; + status = "disabled"; + }; + @@ -4020,6 +4017,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + interrupts-extended = <&intc1_4 18>; + no-loopback-test; + pinctrl-names = "default"; ++ dma-channel = <11>; + status = "disabled"; + }; + @@ -4049,10 +4047,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + ltpi0: ltpi@14c34000 { + compatible = "aspeed-ltpi"; -+ reg = <0x0 0x14c34000 0x0 0x100>; ++ reg = <0x0 0x14c34000 0x0 0x200>, ++ <0x0 0x14c34200 0x0 0x100>, ++ <0x0 0x14c34800 0x0 0x100>; ++ reg-names = "base", "phy", "top"; + clocks = <&syscon1 SCU1_CLK_GATE_LTPICLK>, + <&syscon1 SCU1_CLK_GATE_LTPIPHYCLK>; + clock-names = "ahb", "phy"; ++ aspeed,scu = <&syscon1>; + resets = <&syscon1 SCU1_RESET_LTPI0>; + interrupts-extended = <&intc1_5 12>; + status = "disabled"; @@ -4072,10 +4074,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + + ltpi1: ltpi@14c35000 { + compatible = "aspeed-ltpi"; -+ reg = <0x0 0x14c35000 0x0 0x100>; ++ reg = <0x0 0x14c35000 0x0 0x200>, ++ <0x0 0x14c35200 0x0 0x100>, ++ <0x0 0x14c35800 0x0 0x100>; ++ reg-names = "base", "phy", "top"; + clocks = <&syscon1 SCU1_CLK_GATE_LTPICLK>, + <&syscon1 SCU1_CLK_GATE_LTPI1TXCLK>; + clock-names = "ahb", "phy"; ++ aspeed,scu = <&syscon1>; + resets = <&syscon1 SCU1_RESET_LTPI1>; + interrupts-extended = <&intc1_5 13>; + status = "disabled"; @@ -4155,7 +4161,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + reg = <0x0 0x23800000 0x0 0x94>; + interrupts-extended = <&intc1_5 7>; + pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_fsi1_default>; ++ pinctrl-0 = <&pinctrl_fsi2_default>; + clocks = <&syscon1 SCU1_CLK_GATE_FSICLK>; + resets = <&syscon1 SCU1_RESET_FSI>; + status = "disabled"; @@ -4189,10 +4195,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c0: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x100 0x80>, <0x1A0 0x20>; ++ reg = <0x100 0xA0>, <0x1C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 0>; @@ -4206,10 +4211,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c1: i2c-bus@200 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x200 0x80>, <0x2A0 0x20>; ++ reg = <0x200 0xA0>, <0x2C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 1>; @@ -4223,10 +4227,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c2: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x300 0x80>, <0x3A0 0x20>; ++ reg = <0x300 0xA0>, <0x3C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 2>; @@ -4240,7 +4243,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c3: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x400 0x80>, <0x4A0 0x20>; ++ reg = <0x400 0xA0>, <0x4C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + clocks = <&syscon1 SCU1_CLK_APB>; @@ -4256,10 +4259,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c4: i2c-bus@500 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x500 0x80>, <0x5A0 0x20>; ++ reg = <0x500 0xA0>, <0x5C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + clock-frequency = <100000>; @@ -4273,10 +4275,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c5: i2c-bus@600 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x600 0x80>, <0x6A0 0x20>; ++ reg = <0x600 0xA0>, <0x6C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 5>; @@ -4290,10 +4291,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c6: i2c-bus@700 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x700 0x80>, <0x7A0 0x20>; ++ reg = <0x700 0xA0>, <0x7C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 6>; @@ -4307,10 +4307,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c7: i2c-bus@800 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x800 0x80>, <0x8A0 0x20>; ++ reg = <0x800 0xA0>, <0x8C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 7>; @@ -4324,10 +4323,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c8: i2c-bus@900 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x900 0x80>, <0x9A0 0x20>; ++ reg = <0x900 0xA0>, <0x9C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 8>; @@ -4341,10 +4339,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c9: i2c-bus@a00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xA00 0x80>, <0xAA0 0x20>; ++ reg = <0xA00 0xA0>, <0xAC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 9>; @@ -4358,10 +4355,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c10: i2c-bus@b00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xB00 0x80>, <0xBA0 0x20>; ++ reg = <0xB00 0xA0>, <0xBC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 10>; @@ -4375,10 +4371,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c11: i2c-bus@c00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xC00 0x80>, <0xCA0 0x20>; ++ reg = <0xC00 0xA0>, <0xCC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 11>; @@ -4392,10 +4387,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c12: i2c-bus@d00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xD00 0x80>, <0xDA0 0x20>; ++ reg = <0xD00 0xA0>, <0xDC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 12>; @@ -4409,10 +4403,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c13: i2c-bus@e00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xE00 0x80>, <0xEA0 0x20>; ++ reg = <0xE00 0xA0>, <0xEC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 13>; @@ -4426,10 +4419,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c14: i2c-bus@f00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xF00 0x80>, <0xFA0 0x20>; ++ reg = <0xF00 0xA0>, <0xFC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 14>; @@ -4443,10 +4435,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + i2c15: i2c-bus@1000 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x1000 0x80>, <0x10A0 0x20>; ++ reg = <0x1000 0xA0>, <0x10C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; -+ aspeed,enable-dma; + clocks = <&syscon1 SCU1_CLK_APB>; + resets = <&syscon1 SCU1_RESET_I2C>; + interrupts-extended = <&intc1_2 15>; @@ -4459,7 +4450,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi 2026-09-09 15:51:27.102504264 +0000 @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -4872,8 +4863,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi b/arch/arm64/b +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,659 @@ ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi 2026-09-09 15:51:27.102504264 +0000 +@@ -0,0 +1,660 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include @@ -4974,6 +4965,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + reg= <0x0 0x30c09000 0x0 0x40>; + clocks = <<pi0_syscon AST1700_CLK_AHB>; + resets = <<pi0_syscon AST1700_RESET_JTAG1>; ++ interrupts-extended = <<pi0_intc1_0 23>; + status = "disabled"; + }; + @@ -5264,7 +5256,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c0: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x100 0x80>, <0x1a0 0x20>; ++ reg = <0x100 0xA0>, <0x1C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5281,7 +5273,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c1: i2c-bus@200 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x200 0x80>, <0x2a0 0x20>; ++ reg = <0x200 0xA0>, <0x2C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5298,7 +5290,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c2: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x300 0x80>, <0x3a0 0x20>; ++ reg = <0x300 0xA0>, <0x3C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5315,7 +5307,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c3: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x400 0x80>, <0x4a0 0x20>; ++ reg = <0x400 0xA0>, <0x4C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5332,7 +5324,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c4: i2c-bus@500 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x500 0x80>, <0x5a0 0x20>; ++ reg = <0x500 0xA0>, <0x5C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5349,7 +5341,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c5: i2c-bus@600 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x600 0x80>, <0x6a0 0x20>; ++ reg = <0x600 0xA0>, <0x6C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5366,7 +5358,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c6: i2c-bus@700 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x700 0x80>, <0x7a0 0x20>; ++ reg = <0x700 0xA0>, <0x7C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5383,7 +5375,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c7: i2c-bus@800 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x800 0x80>, <0x8a0 0x20>; ++ reg = <0x800 0xA0>, <0x8C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5400,7 +5392,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c8: i2c-bus@900 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x900 0x80>, <0x9a0 0x20>; ++ reg = <0x900 0xA0>, <0x9C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5417,7 +5409,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c9: i2c-bus@a00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xa00 0x80>, <0xaa0 0x20>; ++ reg = <0xA00 0xA0>, <0xAC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5434,7 +5426,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c10: i2c-bus@b00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xb00 0x80>, <0xba0 0x20>; ++ reg = <0xB00 0xA0>, <0xBC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5451,7 +5443,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c11: i2c-bus@c00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xc00 0x80>, <0xca0 0x20>; ++ reg = <0xC00 0xA0>, <0xCC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5468,7 +5460,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c12: i2c-bus@d00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xd00 0x80>, <0xda0 0x20>; ++ reg = <0xD00 0xA0>, <0xDC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5485,7 +5477,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c13: i2c-bus@e00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xe00 0x80>, <0xea0 0x20>; ++ reg = <0xE00 0xA0>, <0xEC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5502,7 +5494,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c14: i2c-bus@f00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xf00 0x80>, <0xfa0 0x20>; ++ reg = <0xF00 0xA0>, <0xFC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5519,7 +5511,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ + ltpi0_i2c15: i2c-bus@1000 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x1000 0x80>, <0x10a0 0x20>; ++ reg = <0x1000 0xA0>, <0x10C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5535,7 +5527,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/ +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi 2026-09-09 15:51:27.102504264 +0000 @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -5948,8 +5940,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi b/arch/arm64/b +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,659 @@ ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi 2026-09-09 15:51:27.102504264 +0000 +@@ -0,0 +1,660 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include @@ -6050,6 +6042,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + reg= <0x0 0x50c09000 0x0 0x40>; + clocks = <<pi1_syscon AST1700_CLK_AHB>; + resets = <<pi1_syscon AST1700_RESET_JTAG1>; ++ interrupts-extended = <<pi1_intc1_0 23>; + status = "disabled"; + }; + @@ -6340,7 +6333,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c0: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <1>; -+ reg = <0x100 0x80>, <0x1a0 0x20>; ++ reg = <0x100 0xA0>, <0x1C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6357,7 +6350,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c1: i2c-bus@200 { + #address-cells = <1>; + #size-cells = <1>; -+ reg = <0x200 0x80>, <0x2a0 0x20>; ++ reg = <0x200 0xA0>, <0x2C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6374,7 +6367,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c2: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x300 0x80>, <0x3a0 0x20>; ++ reg = <0x300 0xA0>, <0x3C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6391,7 +6384,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c3: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x400 0x80>, <0x4a0 0x20>; ++ reg = <0x400 0xA0>, <0x4C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6408,7 +6401,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c4: i2c-bus@500 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x500 0x80>, <0x5a0 0x20>; ++ reg = <0x500 0xA0>, <0x5C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6425,7 +6418,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c5: i2c-bus@600 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x600 0x80>, <0x6a0 0x20>; ++ reg = <0x600 0xA0>, <0x6C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6442,7 +6435,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c6: i2c-bus@700 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x700 0x80>, <0x7a0 0x20>; ++ reg = <0x700 0xA0>, <0x7C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6459,7 +6452,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c7: i2c-bus@800 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x800 0x80>, <0x8a0 0x20>; ++ reg = <0x800 0xA0>, <0x8C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6476,7 +6469,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c8: i2c-bus@900 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x900 0x80>, <0x9a0 0x20>; ++ reg = <0x900 0xA0>, <0x9C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6493,7 +6486,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c9: i2c-bus@a00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xa00 0x80>, <0xaa0 0x20>; ++ reg = <0xA00 0xA0>, <0xAC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6510,7 +6503,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c10: i2c-bus@b00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xb00 0x80>, <0xba0 0x20>; ++ reg = <0xB00 0xA0>, <0xBC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6527,7 +6520,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c11: i2c-bus@c00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xc00 0x80>, <0xca0 0x20>; ++ reg = <0xC00 0xA0>, <0xCC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6544,7 +6537,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c12: i2c-bus@d00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xd00 0x80>, <0xda0 0x20>; ++ reg = <0xD00 0xA0>, <0xDC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6561,7 +6554,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c13: i2c-bus@e00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xe00 0x80>, <0xea0 0x20>; ++ reg = <0xE00 0xA0>, <0xEC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6578,7 +6571,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c14: i2c-bus@f00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xf00 0x80>, <0xfa0 0x20>; ++ reg = <0xF00 0xA0>, <0xFC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6595,7 +6588,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ + ltpi1_i2c15: i2c-bus@1000 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x1000 0x80>, <0x10a0 0x20>; ++ reg = <0x1000 0xA0>, <0x10C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6611,7 +6604,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/ +}; diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi --- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi 2026-09-09 15:51:27.102504264 +0000 @@ -0,0 +1,647 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include @@ -6991,7 +6984,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c0: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x100 0x80>, <0x1a0 0x20>; ++ reg = <0x100 0xA0>, <0x1C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7008,7 +7001,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c1: i2c-bus@200 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x200 0x80>, <0x2a0 0x20>; ++ reg = <0x200 0xA0>, <0x2C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7025,7 +7018,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c2: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x300 0x80>, <0x3a0 0x20>; ++ reg = <0x300 0xA0>, <0x3C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7042,7 +7035,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c3: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x400 0x80>, <0x4a0 0x20>; ++ reg = <0x400 0xA0>, <0x4C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7059,7 +7052,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c4: i2c-bus@500 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x500 0x80>, <0x5a0 0x20>; ++ reg = <0x500 0xA0>, <0x5C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7076,7 +7069,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c5: i2c-bus@600 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x600 0x80>, <0x6a0 0x20>; ++ reg = <0x600 0xA0>, <0x6C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7093,7 +7086,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c6: i2c-bus@700 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x700 0x80>, <0x7a0 0x20>; ++ reg = <0x700 0xA0>, <0x7C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7110,7 +7103,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c7: i2c-bus@800 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x800 0x80>, <0x8a0 0x20>; ++ reg = <0x800 0xA0>, <0x8C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7127,7 +7120,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c8: i2c-bus@900 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x900 0x80>, <0x9a0 0x20>; ++ reg = <0x900 0xA0>, <0x9C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7144,7 +7137,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c9: i2c-bus@a00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xa00 0x80>, <0xaa0 0x20>; ++ reg = <0xA00 0xA0>, <0xAC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7161,7 +7154,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c10: i2c-bus@b00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xb00 0x80>, <0xba0 0x20>; ++ reg = <0xB00 0xA0>, <0xBC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7178,7 +7171,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c11: i2c-bus@c00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xc00 0x80>, <0xca0 0x20>; ++ reg = <0xC00 0xA0>, <0xCC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7195,7 +7188,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c12: i2c-bus@d00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xd00 0x80>, <0xda0 0x20>; ++ reg = <0xD00 0xA0>, <0xDC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7212,7 +7205,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c13: i2c-bus@e00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xe00 0x80>, <0xea0 0x20>; ++ reg = <0xE00 0xA0>, <0xEC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7229,7 +7222,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c14: i2c-bus@f00 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0xf00 0x80>, <0xfa0 0x20>; ++ reg = <0xF00 0xA0>, <0xFC0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7246,7 +7239,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d + ltpi0_i2c15: i2c-bus@1000 { + #address-cells = <1>; + #size-cells = <0>; -+ reg = <0x1000 0x80>, <0x10a0 0x20>; ++ reg = <0x1000 0xA0>, <0x10C0 0x40>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7262,8 +7255,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/d +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts b/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,97 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts 2026-09-09 15:51:27.102504264 +0000 +@@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -7361,10 +7354,48 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts b/arch/arm64/boot/dt +&pcie1 { + status = "okay"; +}; ++ ++&mdio0 { ++ status = "disabled"; ++}; ++ ++&mac0 { ++ status = "disabled"; ++}; ++ ++&mdio2 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ethphy2: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; ++ ++&sgmii { ++ status = "okay"; ++}; ++ ++&mac2 { ++ status = "okay"; ++ ++ phy-mode = "sgmii"; ++ phy-handle = <ðphy2>; ++}; ++ ++&mctp0 { ++ pcie_rc; ++}; ++ ++&mctp1 { ++ pcie_rc; ++}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,978 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,991 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -7860,13 +7891,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ + pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; +}; + -+&syscon1 { -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; -+}; -+ +&jtag1 { + status = "okay"; +}; @@ -7956,6 +7980,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ + perif-mcyc-enable; + perif-mcyc-src-addr = <0x0 0x98000000>; + perif-mcyc-size = <0x0 0x10000>; ++ vw-pltrst-monitor; + oob-dma-mode; + flash-dma-mode; +}; @@ -7971,6 +7996,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ + perif-mcyc-enable; + perif-mcyc-src-addr = <0x0 0x98000000>; + perif-mcyc-size = <0x0 0x10000>; ++ vw-pltrst-monitor; + oob-dma-mode; + flash-dma-mode; +}; @@ -8085,6 +8111,22 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ +}; + +&hace { ++ dummy-key0 = < ++ 0x89878915 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key1 = < ++ 0x89878902 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key2 = < ++ 0x2C914FA3 0x1056D87B 0xC13D6AE2 0x5E44AF98 ++ 0x0DB97321 0xCA378CF6 0x62EE115D 0x3FA74B90 ++ >; ++ dummy-key3 = < ++ 0x9E18D25C 0x6FB17A43 0x348DE520 0x1269FAC7 ++ 0xAC5503DE 0x2DB61F88 0xEF9AC074 0xB84E6731 ++ >; + status = "okay"; +}; + @@ -8290,34 +8332,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ + status = "okay"; +}; + -+&uphy3a { -+ status = "okay"; -+}; -+ -+&uphy3b { -+ status = "okay"; -+}; -+ +&vhuba0 { + status = "okay"; + pinctrl-0 = <&pinctrl_usb2ahpd0_default>; +}; + -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; -+ -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ -+&vhubb1 { ++&vhubb0 { + status = "okay"; ++ pinctrl-0 = <&pinctrl_usb2bhpd0_default>; +}; + +&vhubc { @@ -8343,9 +8365,31 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ +&otp { + status = "okay"; +}; ++ ++#if 0 ++&soc0 { ++ mbox-ssp-0 { ++ compatible = "aspeed,aspeed-mbox"; ++ reg = <0x4 0x31480000 0x0 0x200000>, <0x0 0x10001000 0x0 0x1000>; ++ mboxes = <&mbox0 0>; ++ aspeed,tx-timeout = <100>; ++ }; ++}; ++#endif ++ ++#if 1 ++&soc0 { ++ mbox-bootmcu-1 { ++ compatible = "aspeed,aspeed-mbox"; ++ reg = <0x4 0x31880000 0x0 0x100000>, <0x4 0x31980000 0x0 0x100000>; ++ mboxes = <&mbox2 1>; ++ aspeed,tx-timeout = <10000>; ++ }; ++}; ++#endif diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts 2026-09-09 15:51:27.103504249 +0000 @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -8567,7 +8611,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts b/arc +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts 2026-09-09 15:51:27.103504249 +0000 @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9027,7 +9071,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts b/arch/arm +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts 2026-09-09 15:51:27.103504249 +0000 @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9467,7 +9511,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts b/arch/arm +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts 2026-09-09 15:51:27.103504249 +0000 @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9511,8 +9555,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts b/arch/arm64/boo + diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,367 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "ast2700-evb.dts" @@ -9583,6 +9627,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9595,6 +9640,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9607,6 +9653,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9619,6 +9666,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9631,6 +9679,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9643,6 +9692,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9655,6 +9705,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9663,10 +9714,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + +&i2c7 { + clock-frequency = <1000000>; -+ debounce-level = <4>; ++ debounce-level = <8>; + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9679,6 +9731,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9691,6 +9744,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9699,10 +9753,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + +&i2c10 { + clock-frequency = <1000000>; -+ debounce-level = <4>; ++ debounce-level = <8>; + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9715,6 +9770,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9727,6 +9783,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9739,6 +9796,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9751,6 +9809,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9759,10 +9818,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts + +&i2c15 { + clock-frequency = <1000000>; -+ debounce-level = <4>; ++ debounce-level = <8>; + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@10 { + compatible = "mctp-i2c-controller"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; @@ -9882,8 +9942,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts b/arch/arm64/boot/dts +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,465 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "ast2700-evb.dts" @@ -10016,6 +10076,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10028,6 +10089,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10040,6 +10102,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10052,6 +10115,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10064,6 +10128,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10076,6 +10141,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10088,6 +10154,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10096,10 +10163,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + +&i2c7 { + clock-frequency = <1000000>; -+ debounce-level = <4>; ++ debounce-level = <8>; + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10112,6 +10180,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10124,6 +10193,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10132,10 +10202,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + +&i2c10 { + clock-frequency = <1000000>; -+ debounce-level = <4>; ++ debounce-level = <8>; + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10148,6 +10219,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10160,6 +10232,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10172,6 +10245,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10184,6 +10258,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10192,10 +10267,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + +&i2c15 { + clock-frequency = <1000000>; -+ debounce-level = <4>; ++ debounce-level = <8>; + status = "okay"; + multi-master; + mctp-controller; ++ aspeed,transfer-mode = "buff"; + mctp@12 { + compatible = "mctp-i2c-controller"; + reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; @@ -10319,10 +10395,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + mac1-clk-delay = <0 0 + 0 0 + 0 0>; -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; +}; + +&vhuba0 { @@ -10330,29 +10402,38 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts + pinctrl-0 = <&pinctrl_usb2ad0_default>; +}; + -+&uphy2a { ++&vhubb0 { + status = "okay"; ++ pinctrl-0 = <&pinctrl_usb2bd0_default>; +}; + -+&usb3ahp { ++&vhubb1 { + status = "disabled"; +}; + -+&usb3bhp { ++&vhubc { + status = "disabled"; +}; + -+&vhubb0 { ++&vhubd { + status = "okay"; +}; + -+&vhubb1 { ++&ehci2 { ++ status = "okay"; ++}; ++ ++&ehci3 { + status = "disabled"; +}; ++ ++&pcie2 { ++ status = "okay"; ++}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,1270 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,1307 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -10364,7 +10445,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as +#define DUAL_NODE 0 // 1: DUAL_NODE, 0: SINGLE_NODE +#define PCIE0_EP 1 // 1: EP, 0: RC +#define PCIE1_EP 1 // 1: EP, 0: RC -+#define PCIE2_RC 1 // 1: RC, 0: SGMII + +/ { + model = "AST2700 EVB"; @@ -10400,6 +10480,20 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + reusable; + }; + ++ rvas_memory0: rvas0{ ++ size = <0x0 0x04000000>; ++ alignment = <0x0 0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ rvas_memory1: rvas1{ ++ size = <0x0 0x04000000>; ++ alignment = <0x0 0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ +#if 0 + gfx_memory: framebuffer { + size = <0x0 0x01000000>; @@ -10624,7 +10718,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default + &pinctrl_adc10_default &pinctrl_adc11_default + &pinctrl_adc12_default &pinctrl_adc13_default -+ &pinctrl_adc14_default &pinctrl_adc15_default>; ++ &pinctrl_adc14_default &pinctrl_adc15_default ++ &pinctrl_adc13_bias>; +}; + +&pinctrl0 { @@ -10710,6 +10805,10 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + "C18", "C6", "C7", "D7", "N13", "C8"; + drive-strength = <1>; + }; ++ pinctrl_adc13_bias: adc13-bias { ++ pins = "W14"; ++ bias-disable; ++ }; +}; + +&gpio1 { @@ -11080,13 +11179,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as +#endif +#endif + -+&syscon1 { -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; -+}; -+ +&espi0 { + status = "okay"; + perif-dma-mode; @@ -11099,6 +11191,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + perif-mcyc-size = <0x0 0x10000>; + memory-region = <&espi0_mcyc_memory>; + perif-rtc-enable; ++ vw-pltrst-monitor; + oob-dma-mode; + flash-dma-mode; +#if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten @@ -11136,6 +11229,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + perif-mcyc-src-addr = <0x0 0x98000000>; + perif-mcyc-size = <0x0 0x10000>; + perif-rtc-enable; ++ vw-pltrst-monitor; + oob-dma-mode; + flash-dma-mode; +#if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten @@ -11258,6 +11352,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + status = "okay"; +}; + ++#if 1 +&video0 { + status = "okay"; + memory-region = <&video_engine_memory0>; @@ -11267,6 +11362,17 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + status = "okay"; + memory-region = <&video_engine_memory1>; +}; ++#else ++&rvas0{ ++ status = "okay"; ++ memory-region = <&rvas_memory0>; ++}; ++ ++&rvas1{ ++ status = "okay"; ++ memory-region = <&rvas_memory1>; ++}; ++#endif + +&disp_intf { + status = "okay"; @@ -11285,6 +11391,22 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as +}; + +&hace { ++ dummy-key0 = < ++ 0x89878915 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key1 = < ++ 0x89878902 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key2 = < ++ 0x2C914FA3 0x1056D87B 0xC13D6AE2 0x5E44AF98 ++ 0x0DB97321 0xCA378CF6 0x62EE115D 0x3FA74B90 ++ >; ++ dummy-key3 = < ++ 0x9E18D25C 0x6FB17A43 0x348DE520 0x1269FAC7 ++ 0xAC5503DE 0x2DB61F88 0xEF9AC074 0xB84E6731 ++ >; + status = "okay"; +}; + @@ -11348,8 +11470,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + status = "okay"; + memory-region = <&pcie0_mmbi0_memory>; + -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#else /* !PCIE0_EP */ +&pcie0 { @@ -11417,8 +11545,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + status = "okay"; + memory-region = <&pcie1_mmbi4_memory>; + -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#else /* !PCIE1_EP */ +&pcie1 { @@ -11526,12 +11660,11 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + +&uhci0 { + status = "okay"; -+ memory-region = <&uhci0_reserved>; +}; + +#endif + -+#if 1 ++#if 0 +&uphy3a { + status = "okay"; +}; @@ -11539,9 +11672,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as +&uphy3b { + status = "okay"; +}; -+#endif + -+#if 0 +&xhci0 { + status = "okay"; +}; @@ -11556,21 +11687,9 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + pinctrl-0 = <&pinctrl_usb2ahpd0_default>; +}; + -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; -+ -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ -+&vhubb1 { ++&vhubb0 { + status = "okay"; ++ pinctrl-0 = <&pinctrl_usb2bhpd0_default>; +}; + +&vhubc { @@ -11587,7 +11706,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + +&uhci1 { + status = "okay"; -+ memory-region = <&uhci1_reserved>; +}; + +&wdt0 { @@ -11623,1193 +11741,692 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + }; +}; +#endif -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts ---- a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,1179 @@ +diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb-dual.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb-dual.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb-dual.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb-dual.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; + -+#include "aspeed-g7.dtsi" -+#include -+#include -+#define PCIE0_EP 1 // 1: EP, 0: RC -+#define PCIE1_EP 1 // 1: EP, 0: RC ++#include "ast2700-evb_ast1700-evb.dts" ++#include "aspeed-ltpi1.dtsi" + +/ { -+ model = "AST2700-EVB"; -+ compatible = "aspeed,ast2700-evb", "aspeed,ast2700"; -+ -+ chosen { -+ stdout-path = "serial12:115200n8"; -+ }; -+ -+ memory@400000000 { -+ device_type = "memory"; -+ reg = <0x4 0x00000000 0x0 0x40000000>; -+ }; -+ -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ #include "ast2700-reserved-mem.dtsi" -+ -+ video_engine_memory0: video0 { -+ size = <0x0 0x02c00000>; -+ alignment = <0x0 0x00100000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+ video_engine_memory1: video1{ -+ size = <0x0 0x02c00000>; -+ alignment = <0x0 0x00100000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+ gfx_memory: framebuffer { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+ xdma_memory0: xdma0 { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ no-map; -+ }; -+ -+ xdma_memory1: xdma1 { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ no-map; -+ }; -+ }; -+ -+ fan0: pwm-fan0 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 0 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan1: pwm-fan1 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 1 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan2: pwm-fan2 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 2 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan3: pwm-fan3 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 3 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan4: pwm-fan4 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 4 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan5: pwm-fan5 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 5 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan6: pwm-fan6 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 6 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan7: pwm-fan7 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 7 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan8: pwm-fan8 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 8 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; ++ model = "AST2700-EVB_AST1700-EVB-DUAL"; + -+ iio-hwmon { ++ ltpi1-iio-hwmon { + compatible = "iio-hwmon"; -+ status = "okay"; -+ io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, -+ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, -+ <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>, -+ <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>; ++ io-channels = <<pi1_adc0 0>, <<pi1_adc0 1>, <<pi1_adc0 2>, <<pi1_adc0 3>, ++ <<pi1_adc0 4>, <<pi1_adc0 5>, <<pi1_adc0 6>, <<pi1_adc0 7>, ++ <<pi1_adc1 0>, <<pi1_adc1 1>, <<pi1_adc1 2>, <<pi1_adc1 3>, ++ <<pi1_adc1 4>, <<pi1_adc1 5>, <<pi1_adc1 6>, <<pi1_adc1 7>; + }; +}; + -+&pwm_tach { ++<pi1_adc0 { ++ aspeed,int-vref-microvolt = <2500000>; + status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default -+ &pinctrl_pwm2_default &pinctrl_pwm3_default -+ &pinctrl_pwm4_default &pinctrl_pwm5_default -+ &pinctrl_pwm6_default &pinctrl_pwm7_default -+ &pinctrl_pwm8_default -+ &pinctrl_tach0_default &pinctrl_tach1_default -+ &pinctrl_tach2_default &pinctrl_tach3_default -+ &pinctrl_tach4_default &pinctrl_tach5_default -+ &pinctrl_tach6_default &pinctrl_tach7_default -+ &pinctrl_tach8_default &pinctrl_tach9_default -+ &pinctrl_tach10_default &pinctrl_tach11_default -+ &pinctrl_tach12_default &pinctrl_tach13_default -+ &pinctrl_tach14_default &pinctrl_tach15_default>; -+ fan-0 { -+ tach-ch = /bits/ 8 <0x0>; -+ }; -+ fan-1 { -+ tach-ch = /bits/ 8 <0x1>; -+ }; -+ fan-2 { -+ tach-ch = /bits/ 8 <0x2>; -+ }; -+ fan-3 { -+ tach-ch = /bits/ 8 <0x3>; -+ }; -+ fan-4 { -+ tach-ch = /bits/ 8 <0x4>; -+ }; -+ fan-5 { -+ tach-ch = /bits/ 8 <0x5>; -+ }; -+ fan-6 { -+ tach-ch = /bits/ 8 <0x6>; -+ }; -+ fan-7 { -+ tach-ch = /bits/ 8 <0x7>; -+ }; -+ fan-8 { -+ tach-ch = /bits/ 8 <0x8>; -+ }; -+ fan-9 { -+ tach-ch = /bits/ 8 <0x9>; -+ }; -+ fan-10 { -+ tach-ch = /bits/ 8 <0xA>; -+ }; -+ fan-11 { -+ tach-ch = /bits/ 8 <0xB>; -+ }; -+ fan-12 { -+ tach-ch = /bits/ 8 <0xC>; -+ }; -+ fan-13 { -+ tach-ch = /bits/ 8 <0xD>; -+ }; -+ fan-14 { -+ tach-ch = /bits/ 8 <0xE>; -+ }; -+ fan-15 { -+ tach-ch = /bits/ 8 <0xF>; -+ }; +}; + -+&mctp0 { ++<pi1_adc1 { ++ aspeed,int-vref-microvolt = <2500000>; + status = "okay"; -+ memory-region = <&mctp0_reserved>; +}; + -+&mctp1 { ++<pi1 { ++ i2c-tunneling = <0x0>; + status = "okay"; -+ memory-region = <&mctp1_reserved>; +}; + -+&mctp2 { ++<pi1_gpio { + status = "okay"; -+ memory-region = <&mctp2_reserved>; +}; + -+&sgpiom0 { ++<pi1_i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&sgpiom1 { ++<pi1_i3c1 { ++ initial-role = "primary"; + status = "okay"; +}; + -+&jtag1 { ++<pi1_i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&adc0 { -+ aspeed,int-vref-microvolt = <2500000>; ++<pi1_i3c3 { ++ initial-role = "primary"; + status = "okay"; ++}; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default -+ &pinctrl_adc2_default &pinctrl_adc3_default -+ &pinctrl_adc4_default &pinctrl_adc5_default -+ &pinctrl_adc6_default &pinctrl_adc7_default>; ++<pi1_i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; +}; + -+&adc1 { -+ aspeed,int-vref-microvolt = <2500000>; ++<pi1_i3c5 { ++ initial-role = "primary"; + status = "okay"; ++}; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default -+ &pinctrl_adc10_default &pinctrl_adc11_default -+ &pinctrl_adc12_default &pinctrl_adc13_default -+ &pinctrl_adc14_default &pinctrl_adc15_default>; -+}; -+ -+&pinctrl1 { -+ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { -+ pins = "U25"; -+ power-source = <1800>; -+ }; -+ -+ pinctrl_i3c0_driving: i3c0-driving { -+ pins = "U25", "U26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c1_driving: i3c1-driving { -+ pins = "Y26", "AA24"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c2_driving: i3c2-driving { -+ pins = "R25", "AA26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c3_driving: i3c3-driving { -+ pins = "R26", "Y25"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c12_15_hv_voltage: i3chv-voltage { -+ pins = "W25"; -+ power-source = <1800>; -+ }; -+ -+ pinctrl_i3c12_driving: i3c12-driving { -+ pins = "W25", "Y23"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c13_driving: i3c13-driving { -+ pins = "Y24", "W21"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c14_driving: i3c14-driving { -+ pins = "AA23", "AC22"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c15_driving: i3c15-driving { -+ pins = "AB22", "Y21"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_rgmii0_driving: rgmii0-driving { -+ pins = "C20", "C19", "A8", "R14", "A7", "P14", -+ "D20", "A6", "B6", "N14", "B7", "B8"; -+ drive-strength = <1>; -+ }; -+ -+ pinctrl_rgmii1_driving: rgmii1-driving { -+ pins = "D19", "C19", "D15", "B12", "B10", "P13", -+ "C18", "C6", "C7", "D7", "N13", "C8"; -+ drive-strength = <1>; -+ }; -+}; -+ -+&gpio0 { -+ pinctrl-0 = <&pinctrl_i3c0_3_hv_voltage &pinctrl_i3c12_15_hv_voltage -+ &pinctrl_i3c0_driving &pinctrl_i3c1_driving -+ &pinctrl_i3c2_driving &pinctrl_i3c3_driving -+ &pinctrl_i3c12_driving &pinctrl_i3c13_driving -+ &pinctrl_i3c14_driving &pinctrl_i3c15_driving>; -+ pinctrl-names = "default"; -+}; -+ -+&i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c6 { ++<pi1_i3c6 { + initial-role = "target"; + pid = <0x000007ec 0x06016000>; + dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&i3c7 { ++<pi1_i3c7 { + initial-role = "primary"; + status = "okay"; +}; + -+&i3c8 { ++<pi1_i3c8 { + initial-role = "target"; + pid = <0x000007ec 0x06018000>; + dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&i3c9 { ++<pi1_i3c9 { + initial-role = "primary"; + status = "okay"; +}; + -+&i3c10 { ++<pi1_i3c10 { + initial-role = "target"; + pid = <0x000007ec 0x0601A000>; + dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&i3c11 { ++<pi1_i3c11 { + initial-role = "primary"; + status = "okay"; +}; + -+&i3c12 { ++<pi1_i3c12 { + initial-role = "target"; + pid = <0x000007ec 0x0601C000>; + dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&i3c13 { ++<pi1_i3c13 { + initial-role = "primary"; + status = "okay"; +}; + -+&i3c14 { ++<pi1_i3c14 { + initial-role = "target"; + pid = <0x000007ec 0x0601E000>; + dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&i3c15 { ++<pi1_i3c15 { + initial-role = "primary"; + status = "okay"; +}; + -+&uart12 { -+ status = "okay"; ++&i2c6 { ++ status = "disabled"; +}; + -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "bmc"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+#include "aspeed-evb-flash-layout-128.dtsi" -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+ -+ flash@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; ++&i2c7 { ++ status = "disabled"; +}; + -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; ++// The following I2C buses require enabling according to the ast2700-dcscm.dts. ++// i2c8 / i2c9 / i2c10 + -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; ++&i2c11 { ++ status = "disabled"; +}; + -+&spi1 { ++<pi1_i2c0 { + status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi1:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; +}; + -+#if 1 -+&spi2 { -+ compatible = "aspeed,ast2700-spi-txrx"; -+ pinctrl-0 = <&pinctrl_spi2_default>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ -+ spi-aspeed-full-duplex; -+ -+ tpm0: tpmdev@0 { -+ compatible = "tcg,tpm_tis-spi"; -+ spi-max-frequency = <34000000>; -+ reg = <0>; -+ status = "okay"; -+ }; -+}; -+#else -+&spi2 { -+ compatible = "aspeed,ast2700-spi"; -+ pinctrl-0 = <&pinctrl_spi2_default &pinctrl_spi2_cs1_default>; -+ pinctrl-names = "default"; ++<pi1_i2c1 { + status = "okay"; -+ -+ flash@0 { -+ status = "okay"; -+ reg = < 0 >; -+ compatible = "jedec,spi-nor"; -+ m25p,fast-read; -+ label = "spi2:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ reg = < 1 >; -+ compatible = "jedec,spi-nor"; -+ m25p,fast-read; -+ label = "spi2:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; +}; -+#endif + -+&emmc_controller { ++<pi1_i2c2 { + status = "okay"; -+ mmc-hs200-1_8v; +}; + -+&emmc { ++<pi1_i2c3 { + status = "okay"; -+#if 1 -+ bus-width = <4>; -+#else -+ bus-width = <8>; -+ pinctrl-0 = <&pinctrl_emmc_default -+ &pinctrl_emmcg8_default>; -+#endif -+ non-removable; -+ max-frequency = <200000000>; +}; + -+&ufs_controller { ++<pi1_i2c4 { + status = "okay"; +}; + -+&ufs { ++<pi1_i2c5 { + status = "okay"; -+ lanes-per-direction = <2>; -+ ref-clk-freq = <26000000>; +}; + -+&chassis { ++<pi1_i2c6 { + status = "okay"; +}; + -+&mdio0 { ++<pi1_i2c7 { + status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy0: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; +}; + -+&mdio1 { ++<pi1_i2c8 { + status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy1: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; +}; + -+&mac0 { ++<pi1_i2c9 { + status = "okay"; -+ -+ phy-mode = "rgmii"; -+ phy-handle = <ðphy0>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; +}; + -+&mac1 { ++<pi1_i2c10 { + status = "okay"; -+ -+ phy-mode = "rgmii"; -+ phy-handle = <ðphy1>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_rgmii1_driving>; +}; + -+#if 0 -+&mdio2 { ++<pi1_i2c11 { + status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; +}; + -+&sgmii { ++<pi1_i2c12 { + status = "okay"; +}; + -+&mac2 { ++<pi1_i2c13 { + status = "okay"; -+ -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; +}; + -+&pcie2 { ++<pi1_i2c14 { + status = "okay"; +}; -+#endif -+ -+&syscon1 { -+ mac0-clk-delay = <0x33 0x30 -+ 0x10 0x10 -+ 0x10 0x10>; -+ mac1-clk-delay = <0x31 0x31 -+ 0x10 0x10 -+ 0x10 0x10>; -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; -+}; + -+&espi0 { ++<pi1_i2c15 { + status = "okay"; -+ perif-dma-mode; -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi0_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ oob-dma-mode; -+ flash-dma-mode; +}; + -+&lpc0_kcs0 { ++&uart8 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; + status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <0>; +}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb_ast1700-evb.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,456 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+&lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <1>; -+}; ++/dts-v1/; + -+&lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <2>; -+}; ++#include "ast2700-evb.dts" ++#include "aspeed-ltpi0.dtsi" + -+&lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <3>; -+}; ++/ { ++ model = "AST2700-EVB_AST1700-EVB"; + -+&lpc0_ibt { -+ status = "okay"; -+}; ++ ltpi_fan0: ltpi-pwm-fan0 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 0 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc0_mbox { -+ status = "okay"; -+}; ++ ltpi_fan1: ltpi-pwm-fan1 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 1 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc0_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; ++ ltpi_fan2: ltpi-pwm-fan2 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 2 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc0_uart_routing { -+ status = "okay"; -+}; ++ ltpi_fan3: ltpi-pwm-fan3 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 3 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <4>; -+}; ++ ltpi_fan4: ltpi-pwm-fan4 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 4 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <5>; -+}; ++ ltpi_fan5: ltpi-pwm-fan5 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 5 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <6>; -+}; ++ ltpi_fan6: ltpi-pwm-fan6 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 6 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <7>; -+}; ++ ltpi_fan7: ltpi-pwm-fan7 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 7 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_ibt { -+ status = "okay"; -+}; ++ ltpi_fan8: ltpi-pwm-fan8 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 8 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_mbox { -+ status = "okay"; -+}; ++ ltpi_fan9: ltpi-pwm-fan9 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 9 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&lpc1_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+ -+&lpc1_uart_routing { -+ status = "okay"; -+}; -+ -+&video0 { -+ status = "okay"; -+ memory-region = <&video_engine_memory0>; -+}; -+ -+&video1 { -+ status = "okay"; -+ memory-region = <&video_engine_memory1>; -+}; -+ -+&disp_intf { -+ status = "okay"; -+}; ++ ltpi_fan10: ltpi-pwm-fan10 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 10 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&rtc { -+ status = "okay"; -+}; ++ ltpi_fan11: ltpi-pwm-fan11 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 11 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&rsss { -+ status = "okay"; -+}; ++ ltpi_fan12: ltpi-pwm-fan12 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 12 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&ecdsa { -+ status = "okay"; -+}; ++ ltpi_fan13: ltpi-pwm-fan13 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 13 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&hace { -+ status = "okay"; -+}; ++ ltpi_fan14: ltpi-pwm-fan14 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 14 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+#if PCIE0_EP -+&bmc_dev0 { -+ status = "okay"; -+ memory-region = <&bmc_dev0_memory>; -+}; ++ ltpi_fan15: ltpi-pwm-fan15 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 15 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+&xdma0 { -+ status = "okay"; -+ memory-region = <&xdma_memory0>; ++ ltpi0-iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <<pi0_adc0 0>, <<pi0_adc0 1>, <<pi0_adc0 2>, <<pi0_adc0 3>, ++ <<pi0_adc0 4>, <<pi0_adc0 5>, <<pi0_adc0 6>, <<pi0_adc0 7>, ++ <<pi0_adc1 0>, <<pi0_adc1 1>, <<pi0_adc1 2>, <<pi0_adc1 3>, ++ <<pi0_adc1 4>, <<pi0_adc1 5>, <<pi0_adc1 6>, <<pi0_adc1 7>; ++ }; +}; + -+&pcie_vuart0 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ ++<pi0_pwm_tach { + status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ltpi0_pwm0_default &pinctrl_ltpi0_pwm1_default ++ &pinctrl_ltpi0_pwm2_default &pinctrl_ltpi0_pwm3_default ++ &pinctrl_ltpi0_pwm4_default &pinctrl_ltpi0_pwm5_default ++ &pinctrl_ltpi0_pwm6_default &pinctrl_ltpi0_pwm7_default ++ &pinctrl_ltpi0_pwm8_default ++ &pinctrl_ltpi0_tach0_default &pinctrl_ltpi0_tach1_default ++ &pinctrl_ltpi0_tach2_default &pinctrl_ltpi0_tach3_default ++ &pinctrl_ltpi0_tach4_default &pinctrl_ltpi0_tach5_default ++ &pinctrl_ltpi0_tach6_default &pinctrl_ltpi0_tach7_default ++ &pinctrl_ltpi0_tach8_default &pinctrl_ltpi0_tach9_default ++ &pinctrl_ltpi0_tach10_default &pinctrl_ltpi0_tach11_default ++ &pinctrl_ltpi0_tach12_default &pinctrl_ltpi0_tach13_default ++ &pinctrl_ltpi0_tach14_default &pinctrl_ltpi0_tach15_default>; ++ ltpi_fan0 { ++ tach-ch = /bits/ 8 <0x0>; ++ }; ++ ltpi_fan1 { ++ tach-ch = /bits/ 8 <0x1>; ++ }; ++ ltpi_fan2 { ++ tach-ch = /bits/ 8 <0x2>; ++ }; ++ ltpi_fan3 { ++ tach-ch = /bits/ 8 <0x3>; ++ }; ++ ltpi_fan4 { ++ tach-ch = /bits/ 8 <0x4>; ++ }; ++ ltpi_fan5 { ++ tach-ch = /bits/ 8 <0x5>; ++ }; ++ ltpi_fan6 { ++ tach-ch = /bits/ 8 <0x6>; ++ }; ++ ltpi_fan7 { ++ tach-ch = /bits/ 8 <0x7>; ++ }; ++ ltpi_fan8 { ++ tach-ch = /bits/ 8 <0x8>; ++ }; ++ ltpi_fan9 { ++ tach-ch = /bits/ 8 <0x9>; ++ }; ++ ltpi_fan10 { ++ tach-ch = /bits/ 8 <0xA>; ++ }; ++ ltpi_fan11 { ++ tach-ch = /bits/ 8 <0xB>; ++ }; ++ ltpi_fan12 { ++ tach-ch = /bits/ 8 <0xC>; ++ }; ++ ltpi_fan13 { ++ tach-ch = /bits/ 8 <0xD>; ++ }; ++ ltpi_fan14 { ++ tach-ch = /bits/ 8 <0xE>; ++ }; ++ ltpi_fan15 { ++ tach-ch = /bits/ 8 <0xF>; ++ }; +}; + -+&pcie_vuart1 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; ++&sgpios { ++ /delete-property/ gpio-line-names; +}; + -+&pcie_lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <8>; ++<pi0_gpio { ++ /delete-property/ gpio-line-names; ++ /delete-node/ gpio_17; ++ /delete-node/ gpio_19; ++ /delete-node/ gpio_25; ++ /delete-node/ gpio_53; ++ /delete-node/ gpio_61; ++ /delete-node/ gpio_63; +}; + -+&pcie_lpc0_kcs1 { ++<pi0_adc0 { ++ aspeed,int-vref-microvolt = <2500000>; + status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <9>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ltpi0_adc0_default &pinctrl_ltpi0_adc1_default ++ &pinctrl_ltpi0_adc2_default &pinctrl_ltpi0_adc3_default ++ &pinctrl_ltpi0_adc4_default &pinctrl_ltpi0_adc5_default ++ &pinctrl_ltpi0_adc6_default &pinctrl_ltpi0_adc7_default>; +}; + -+&pcie_lpc0_kcs2 { ++<pi0_adc1 { ++ aspeed,int-vref-microvolt = <2500000>; + status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <10>; ++ pinctrl-0 = <&pinctrl_ltpi0_adc8_default &pinctrl_ltpi0_adc9_default ++ &pinctrl_ltpi0_adc10_default &pinctrl_ltpi0_adc11_default ++ &pinctrl_ltpi0_adc12_default &pinctrl_ltpi0_adc13_default ++ &pinctrl_ltpi0_adc14_default &pinctrl_ltpi0_adc15_default>; +}; + -+&pcie_lpc0_kcs3 { ++<pi0 { ++ i2c-tunneling = <0x0>; + status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <11>; +}; + -+&pcie_lpc0_ibt { ++<pi0_i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; -+ bt-channel = <2>; +}; + -+&pcie0_mmbi0 { -+ status = "okay"; -+ memory-region = <&pcie0_mmbi0_memory>; -+ -+ mmbi-bmc-int-value = /bits/ 8 <0x00>; -+ mmbi-bmc-int-offset = <0x100000>; -+}; -+#else -+&pcie0 { ++<pi0_i3c1 { ++ initial-role = "primary"; + status = "okay"; +}; -+#endif + -+#if PCIE1_EP -+&bmc_dev1 { ++<pi0_i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; -+ memory-region = <&bmc_dev1_memory>; +}; + -+&xdma1 { ++<pi0_i3c3 { ++ initial-role = "primary"; + status = "okay"; -+ memory-region = <&xdma_memory1>; +}; + -+&pcie_vuart2 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ ++<pi0_i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&pcie_vuart3 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; -+ ++<pi0_i3c5 { ++ initial-role = "primary"; + status = "okay"; +}; + -+&pcie_lpc1_kcs0 { ++<pi0_i3c6 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06016000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <12>; +}; + -+&pcie_lpc1_kcs1 { ++<pi0_i3c7 { ++ initial-role = "primary"; + status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <13>; +}; + -+&pcie_lpc1_kcs2 { ++<pi0_i3c8 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06018000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <14>; +}; + -+&pcie_lpc1_kcs3 { ++<pi0_i3c9 { ++ initial-role = "primary"; + status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <15>; +}; + -+&pcie_lpc1_ibt { ++<pi0_i3c10 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601A000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; -+ bt-channel = <3>; +}; + -+&pcie1_mmbi4 { -+ status = "okay"; -+ memory-region = <&pcie1_mmbi4_memory>; -+ -+ mmbi-bmc-int-value = /bits/ 8 <0x44>; -+ mmbi-bmc-int-offset = <0x100400>; -+}; -+#else -+&pcie1 { ++<pi0_i3c11 { ++ initial-role = "primary"; + status = "okay"; +}; -+#endif + -+#if 0 -+&i3c0 { ++<pi0_i3c12 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601C000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; +}; + -+&jtag0 { ++<pi0_i3c13 { ++ initial-role = "primary"; + status = "okay"; +}; -+#endif + -+&sdio_controller { ++<pi0_i3c14 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601E000>; ++ dcr = /bits/ 8 <0xcc>; + status = "okay"; -+ mmc-hs200-1_8v; -+ -+ vcc_sdhci0: regulator-vcc-sdhci0 { -+ compatible = "regulator-fixed"; -+ regulator-name = "SDHCI0 Vcc"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ gpios = <&gpio0 ASPEED_GPIO(G, 6) GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ -+ vccq_sdhci0: regulator-vccq-sdhci0 { -+ compatible = "regulator-gpio"; -+ regulator-name = "SDHCI0 VccQ"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ gpios = <&gpio0 ASPEED_GPIO(G, 7) GPIO_ACTIVE_HIGH>; -+ gpios-states = <1>; -+ states = <3300000 1>, -+ <1800000 0>; -+ }; -+ +}; + -+&sdhci { ++<pi0_i3c15 { ++ initial-role = "primary"; + status = "okay"; -+ bus-width = <4>; -+ max-frequency = <100000000>; -+ /* DDR50 bits in CAPA2 are not supported */ -+ sdhci-caps-mask = <0x6 0x0>; -+ sdhci-drive-type = /bits/ 8 <3>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_sd_default>; -+ vmmc-supply = <&vcc_sdhci0>; -+ vqmmc-supply = <&vccq_sdhci0>; -+ sd-uhs-sdr104; /* enable sdr104 to execute tuning */ +}; + +&i2c0 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; ++ status = "disabled"; +}; + +&i2c1 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; ++ status = "disabled"; +}; + +&i2c2 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; ++ status = "disabled"; +}; + +&i2c3 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; ++ status = "disabled"; +}; + +&i2c4 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; ++ status = "disabled"; +}; + +&i2c5 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c6 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c7 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c8 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c9 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c10 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c11 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c12 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c13 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c14 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+&i2c15 { -+ status = "okay"; -+ clock-frequency = <1000000>; -+ multi-master; -+}; -+ -+#if 0 -+&ehci0 { -+ status = "okay"; ++ status = "disabled"; +}; + -+&ehci1 { ++<pi0_i2c0 { + status = "okay"; +}; + -+&uhci0 { ++<pi0_i2c1 { + status = "okay"; +}; + -+#endif -+ -+#if 1 -+&uphy3a { ++<pi0_i2c2 { + status = "okay"; +}; + -+&uphy3b { ++<pi0_i2c3 { + status = "okay"; +}; -+#endif + -+#if 0 -+&xhci0 { ++<pi0_i2c4 { + status = "okay"; +}; + -+&xhci1 { ++<pi0_i2c5 { + status = "okay"; +}; -+#endif + -+&vhuba0 { ++<pi0_i2c6 { + status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; +}; + -+&usb3ahp { ++<pi0_i2c7 { + status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; +}; + -+&usb3bhp { ++<pi0_i2c8 { + status = "okay"; +}; + -+&uphy2b { ++<pi0_i2c9 { + status = "okay"; +}; + -+&vhubb1 { ++<pi0_i2c10 { + status = "okay"; +}; + -+&vhubc { ++<pi0_i2c11 { + status = "okay"; +}; + -+&ehci3 { ++<pi0_i2c12 { + status = "okay"; +}; + -+&uhci1 { ++<pi0_i2c13 { + status = "okay"; +}; + -+&wdt0 { ++<pi0_i2c14 { + status = "okay"; +}; + -+&wdt1 { ++<pi0_i2c15 { + status = "okay"; +}; + -+&otp { ++&uart3 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; + status = "okay"; +}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts ---- a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,1179 @@ +diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,1174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -13493,10 +13110,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts + mac1-clk-delay = <0x31 0x31 + 0x10 0x10 + 0x10 0x10>; -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; +}; + +&espi0 { @@ -13685,8 +13298,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts + status = "okay"; + memory-region = <&pcie0_mmbi0_memory>; + -+ mmbi-bmc-int-value = /bits/ 8 <0x00>; -+ mmbi-bmc-int-offset = <0x100000>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#else +&pcie0 { @@ -13754,8 +13373,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts + status = "okay"; + memory-region = <&pcie1_mmbi4_memory>; + -+ mmbi-bmc-int-value = /bits/ 8 <0x44>; -+ mmbi-bmc-int-offset = <0x100400>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#else +&pcie1 { @@ -13924,7 +13549,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts + +#endif + -+#if 1 ++#if 0 +&uphy3a { + status = "okay"; +}; @@ -13949,19 +13574,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts + pinctrl-0 = <&pinctrl_usb2ahpd0_default>; +}; + -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; -+ -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ +&vhubb1 { + status = "okay"; +}; @@ -13991,8 +13603,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,1132 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,1127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -14671,10 +14283,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/a + mac1-clk-delay = <0x18 0x17 + 0x10 0x10 + 0x10 0x10>; -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; +}; + +&espi0 { @@ -14863,8 +14471,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/a + status = "okay"; + memory-region = <&pcie0_mmbi0_memory>; + -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#else +&pcie0 { @@ -14932,8 +14546,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/a + status = "okay"; + memory-region = <&pcie1_mmbi4_memory>; + -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#else +&pcie1 { @@ -15057,7 +14677,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/a + +#endif + -+#if 1 ++#if 0 +&uphy3a { + status = "okay"; +}; @@ -15082,19 +14702,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/a + pinctrl-0 = <&pinctrl_usb2ahpd0_default>; +}; + -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; -+ -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ +&vhubb1 { + status = "okay"; +}; @@ -15127,8 +14734,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/a +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts b/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,52 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -15176,14 +14783,10 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts b/arch/arm64/boot/dts/a + mac1-clk-delay = <0 0 + 0 0 + 0 0>; -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-raw.dts b/arch/arm64/boot/dts/aspeed/ast2700-raw.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-raw.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-raw.dts 2025-12-23 10:16:06.862271766 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-raw.dts 2026-09-09 15:51:27.103504249 +0000 @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -15407,8 +15010,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-raw.dts b/arch/arm64/boot/dts/as + diff --git a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi b/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi --- a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,126 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* AST2700 reserved memories with no-map property */ @@ -15437,6 +15040,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi b/arch/arm64/b + +#if PCIE0_EP +bmc_dev0_memory: bmc-dev0-memory@423800000 { ++ compatible = "shared-dma-pool"; + reg = <0x4 0x23800000 0x0 0x100000>; + no-map; +}; @@ -15455,6 +15059,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi b/arch/arm64/b + +#if PCIE1_EP +bmc_dev1_memory: bmc-dev1-memory@423900000 { ++ compatible = "shared-dma-pool"; + reg = <0x4 0x23900000 0x0 0x100000>; + no-map; +}; @@ -15537,8 +15142,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi b/arch/arm64/b +}; diff --git a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts b/arch/arm64/boot/dts/aspeed/ast2700-slt.dts --- a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts 1970-01-01 00:00:00.000000000 +0000 -+++ b/arch/arm64/boot/dts/aspeed/ast2700-slt.dts 2025-12-23 10:16:06.862271766 +0000 -@@ -0,0 +1,857 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-slt.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,850 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -16106,19 +15711,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts b/arch/arm64/boot/dts/as + phy-handle = <ðphy2>; +}; + -+&syscon1 { -+ mac0-clk-delay = <0x1a 0x15 -+ 0x10 0x10 -+ 0x10 0x10>; -+ mac1-clk-delay = <0x19 0x17 -+ 0x10 0x10 -+ 0x10 0x10>; -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; -+}; -+ +&lpc0_kcs0 { + status = "okay"; + kcs-io-addr = <0xca0>; @@ -16246,8 +15838,14 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts b/arch/arm64/boot/dts/as + status = "okay"; + memory-region = <&pcie0_mmbi0_memory>; + -+ mmbi-bmc-int-value = /bits/ 8 <0x00>; -+ mmbi-bmc-int-offset = <0x100000>; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ +}; +#endif + @@ -16396,6861 +15994,7198 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts b/arch/arm64/boot/dts/as +&otp { + status = "okay"; +}; -diff --git a/drivers/Makefile b/drivers/Makefile ---- a/drivers/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/Makefile 2025-12-23 10:16:13.352162932 +0000 -@@ -195,3 +195,4 @@ - obj-$(CONFIG_DPLL) += dpll/ - - obj-$(CONFIG_S390) += s390/ -+obj-$(CONFIG_JTAG_ASPEED) += jtag/ -diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig ---- a/drivers/bus/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/bus/Kconfig 2025-12-23 10:16:08.870238093 +0000 -@@ -261,6 +261,12 @@ - configuration. Allows to adjust the priorities of all master - peripherals. - -+config ASPEED_LTPI -+ bool "Aspeed LTPI bus controller driver" -+ depends on ARCH_ASPEED -+ help -+ LVDS Tunneling Protocol and Interface (LTPI) bus controller -+ - source "drivers/bus/fsl-mc/Kconfig" - source "drivers/bus/mhi/Kconfig" - -diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile ---- a/drivers/bus/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/bus/Makefile 2025-12-23 10:16:12.865171099 +0000 -@@ -39,6 +39,7 @@ - obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o - - obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o -+obj-$(CONFIG_ASPEED_LTPI) += aspeed-ltpi.o - - # MHI - obj-y += mhi/ -diff --git a/drivers/bus/aspeed-ltpi.c b/drivers/bus/aspeed-ltpi.c ---- a/drivers/bus/aspeed-ltpi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/bus/aspeed-ltpi.c 2025-12-23 10:16:20.967035301 +0000 -@@ -0,0 +1,272 @@ +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright ASPEED Technology + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++/dts-v1/; + -+#define LTPI_AUTO_CAP_LOW 0x24 -+#define LTPI_I2C_IO_FRAME_EN GENMASK(29, 24) -+#define LTPI_AUTO_CAP_HIGH 0x28 -+#define LTPI_UART_IO_FRAME_EN GENMASK(14, 13) ++#include "ast2700a1-evb.dts" + -+#define LTPI_LINK_CONTROLL 0x80 -+#define LTPI_AUTO_CONFIG BIT(10) ++/ { ++ model = "AST2700A1-CI-HOST"; ++}; + -+#define LTPI_INTR_STATUS 0x100 -+#define LTPI_INTR_EN 0x104 -+#define LTPI_INTR_EN_OP_LINK_LOST BIT(4) -+#define LTPI_LINK_MANAGE_ST 0x108 -+#define LTPI_LINK_PARTNER_FLAG BIT(24) ++&bmc_dev0 { ++ status = "disabled"; ++}; + -+#define LTPI_MANUAL_CAP_LOW 0x118 -+#define LTPI_MANUAL_CAP_HIGH 0x11c ++&xdma0 { ++ status = "disabled"; ++}; + -+#define LTPI_I2C_TIMING_0 0x134 -+#define LTPI_I2C_TIMING_1 0x138 ++&pcie_vuart0 { ++ status = "disabled"; ++}; + -+#define LTPI_I2C_100K_0 0x3535352f -+#define LTPI_I2C_100K_1 0x09353535 ++&pcie_vuart1 { ++ status = "disabled"; ++}; + -+#define LTPI_I2C_400K_0 0x06060d06 -+#define LTPI_I2C_400K_1 0x090d0a06 ++&pcie_lpc0_kcs0 { ++ status = "disabled"; ++}; + -+#define SCU_IO_PINS_TRAP1 0x10 -+#define SCU_IO_PINS_TRAP1_CLEAR 0x14 -+#define SCU_IO_PINS_TRAP_LTPI GENMASK(2, 0) -+#define SCU_IO_OTP_TRAP1 0xa00 -+#define SCU_IO_OTP_TRAP1_CLEAR 0xa04 -+#define SCU_IO_OTP_TRAP2 0xa20 -+#define SCU_IO_OTP_TRAP2_CLEAR 0xa24 ++&pcie_lpc0_kcs1 { ++ status = "disabled"; ++}; + -+#define MAX_I2C_IN_LTPI 6 -+#define MAX_UART_IN_LTPI 2 ++&pcie_lpc0_kcs2 { ++ status = "disabled"; ++}; + -+enum chip_version { -+ AST2700, -+ AST1700, ++&pcie_lpc0_kcs3 { ++ status = "disabled"; +}; + -+struct aspeed_ltpi_priv { -+ struct device *dev; -+ void __iomem *regs; -+ struct clk *ltpi_clk; -+ struct clk *ltpi_phyclk; -+ struct reset_control *ltpi_rst; -+ struct regmap *scu; -+ u32 version; -+ u32 i2c_tunneling; -+ u32 i2c_timing_0; -+ u32 i2c_timing_1; -+ u32 uart_tunneling; ++&pcie_lpc0_ibt { ++ status = "disabled"; +}; + -+static irqreturn_t aspeed_ltpi_irq_handler(int irq, void *dev_id) -+{ -+ struct aspeed_ltpi_priv *priv = dev_id; -+ u32 status = readl(priv->regs + LTPI_INTR_STATUS); ++&pcie0_mmbi0 { ++ status = "disabled"; ++}; + -+ if (status & LTPI_INTR_EN_OP_LINK_LOST) { -+ writel(0, priv->regs + LTPI_INTR_EN); -+ writel(status, priv->regs + LTPI_INTR_STATUS); -+ panic("LTPI link lost!\n"); -+ /* Will not return */ -+ } ++&pcie0 { ++ status = "okay"; ++}; + -+ writel(status, priv->regs + LTPI_INTR_STATUS); ++&bmc_dev1 { ++ status = "disabled"; ++}; + -+ return IRQ_HANDLED; -+} ++&xdma1 { ++ status = "disabled"; ++}; + -+static int aspeed_ltpi_init_mux(struct aspeed_ltpi_priv *priv) -+{ -+ u32 reg, i2c_en, uart_en, i; ++&pcie_vuart2 { ++ status = "disabled"; ++}; + -+ reg = readl(priv->regs + LTPI_AUTO_CAP_LOW); ++&pcie_vuart3 { ++ status = "disabled"; ++}; + -+ i2c_en = FIELD_GET(LTPI_I2C_IO_FRAME_EN, reg); -+ i2c_en &= priv->i2c_tunneling; ++&pcie_lpc1_kcs0 { ++ status = "disabled"; ++}; + -+ reg &= ~LTPI_I2C_IO_FRAME_EN; -+ reg |= FIELD_PREP(LTPI_I2C_IO_FRAME_EN, i2c_en); -+ writel(reg, priv->regs + LTPI_MANUAL_CAP_LOW); ++&pcie_lpc1_kcs1 { ++ status = "disabled"; ++}; + -+ reg = readl(priv->regs + LTPI_AUTO_CAP_HIGH); ++&pcie_lpc1_kcs2 { ++ status = "disabled"; ++}; + -+ uart_en = FIELD_GET(LTPI_UART_IO_FRAME_EN, reg); -+ uart_en &= priv->uart_tunneling; ++&pcie_lpc1_kcs3 { ++ status = "disabled"; ++}; + -+ reg &= ~LTPI_UART_IO_FRAME_EN; -+ reg |= FIELD_PREP(LTPI_UART_IO_FRAME_EN, uart_en); ++&pcie_lpc1_ibt { ++ status = "disabled"; ++}; + -+ writel(reg, priv->regs + LTPI_MANUAL_CAP_HIGH); ++&pcie1_mmbi4 { ++ status = "disabled"; ++}; + -+ /* Apply LTPI manual configuration */ -+ reg = readl(priv->regs + LTPI_LINK_CONTROLL); -+ reg &= ~LTPI_AUTO_CONFIG; -+ writel(reg, priv->regs + LTPI_LINK_CONTROLL); ++&pcie1 { ++ status = "okay"; ++}; + -+ /* Set the AST1700 i2c ac-timing */ -+ if (priv->version == AST1700) { -+ /* Apply i2c timing with i2c tunneling setting */ -+ for (i = 0; i < MAX_I2C_IN_LTPI; i++) { -+ if ((priv->i2c_tunneling >> i) & 0x1) { -+ writel(priv->i2c_timing_0, -+ priv->regs + LTPI_I2C_TIMING_0 + (0x8 * i)); -+ writel(priv->i2c_timing_1, -+ priv->regs + LTPI_I2C_TIMING_1 + (0x8 * i)); -+ } -+ } -+ } ++&mdio0 { ++ status = "disabled"; ++}; + -+ return 0; -+} ++&mac0 { ++ status = "disabled"; ++}; + -+static int aspeed_ltpi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ const struct of_dev_auxdata *lookup = dev_get_platdata(dev); -+ struct device_node *np = dev->of_node; -+ const struct of_device_id *match; -+ struct aspeed_ltpi_priv *priv; -+ int irq, ret; ++&mdio2 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ match = of_match_device(dev->driver->of_match_table, dev); ++ ethphy2: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; + -+ if (match) { -+ if (of_property_match_string(np, "compatible", match->compatible) < 0) -+ return -ENODEV; -+ } else { -+ return -ENODEV; -+ } ++&sgmii { ++ status = "okay"; ++}; + -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++&mac2 { ++ status = "okay"; + -+ priv->dev = dev; -+ priv->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->regs)) -+ return PTR_ERR(priv->regs); ++ phy-mode = "sgmii"; ++ phy-handle = <ðphy2>; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,991 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ priv->version = (enum chip_version)device_get_match_data(dev); ++/dts-v1/; + -+ priv->ltpi_clk = devm_clk_get(&pdev->dev, "ltpi"); -+ if (IS_ERR(priv->ltpi_clk)) { -+ priv->ltpi_clk = devm_clk_get(&pdev->dev, "ahb"); -+ if (IS_ERR(priv->ltpi_clk)) -+ return PTR_ERR(priv->ltpi_clk); ++#include "aspeed-g7.dtsi" ++#include ++#include + -+ clk_prepare_enable(priv->ltpi_clk); ++#define PCIE0_EP 1 // 1: EP, 0: RC ++#define PCIE1_EP 1 // 1: EP, 0: RC + -+ priv->ltpi_phyclk = devm_clk_get(&pdev->dev, "phy"); -+ if (IS_ERR(priv->ltpi_phyclk)) -+ return PTR_ERR(priv->ltpi_phyclk); ++/ { ++ model = "AST2700A1-DCSCM"; ++ compatible = "aspeed,ast2700"; + -+ clk_prepare_enable(priv->ltpi_phyclk); -+ } else { -+ priv->ltpi_phyclk = NULL; -+ } ++ chosen { ++ stdout-path = "serial12:115200n8"; ++ }; + -+ priv->ltpi_rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); -+ if (IS_ERR(priv->ltpi_rst)) -+ return PTR_ERR(priv->ltpi_rst); ++ memory@400000000 { ++ device_type = "memory"; ++ reg = <0x4 0x00000000 0x0 0x40000000>; ++ }; + -+ reset_control_deassert(priv->ltpi_rst); ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; + -+ priv->i2c_tunneling = GENMASK(MAX_I2C_IN_LTPI - 1, 0); -+ if (!of_property_read_u32(np, "i2c-tunneling", &ret)) -+ priv->i2c_tunneling = ret; ++ #include "ast2700-reserved-mem.dtsi" + -+ priv->i2c_timing_0 = LTPI_I2C_100K_0; -+ priv->i2c_timing_1 = LTPI_I2C_100K_1; -+ if (!of_property_read_u32(np, "i2c-tunneling-timing", &ret)) { -+ if (ret == 400) { -+ priv->i2c_timing_0 = LTPI_I2C_400K_0; -+ priv->i2c_timing_1 = LTPI_I2C_400K_1; -+ } -+ } -+ priv->uart_tunneling = GENMASK(MAX_UART_IN_LTPI - 1, 0); -+ if (!of_property_read_u32(np, "uart-tunneling", &ret)) -+ priv->uart_tunneling = ret; ++ video_engine_memory0: video0 { ++ size = <0x0 0x02000000>; ++ alignment = <0x0 0x00010000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; + -+ priv->scu = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); -+ if (of_get_property(np, "remote-controller", NULL)) { -+ u32 reg; ++ video_engine_memory1: video1{ ++ size = <0x0 0x02000000>; ++ alignment = <0x0 0x00010000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; + -+ /* Clear all the pins/otp strap but LTPI related settings for AST1700 */ -+ regmap_read(priv->scu, SCU_IO_PINS_TRAP1, ®); -+ reg &= ~SCU_IO_PINS_TRAP_LTPI; -+ regmap_write(priv->scu, SCU_IO_PINS_TRAP1_CLEAR, reg); ++#if 0 ++ gfx_memory: framebuffer { ++ size = <0x0 0x01000000>; ++ alignment = <0x0 0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++#endif ++ }; + -+ regmap_read(priv->scu, SCU_IO_OTP_TRAP1, ®); -+ regmap_write(priv->scu, SCU_IO_OTP_TRAP1_CLEAR, reg); ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <&adc0 7>, <&adc1 7>; ++ }; ++}; + -+ regmap_read(priv->scu, SCU_IO_OTP_TRAP2, ®); -+ regmap_write(priv->scu, SCU_IO_OTP_TRAP2_CLEAR, reg); -+ } else { -+ irq = platform_get_irq(pdev, 0); -+ ret = devm_request_irq(priv->dev, irq, aspeed_ltpi_irq_handler, -+ 0, dev_name(priv->dev), priv); -+ if (ret) { -+ dev_err(priv->dev, "failed to request irq\n"); -+ reset_control_assert(priv->ltpi_rst); -+ clk_disable_unprepare(priv->ltpi_phyclk); -+ clk_disable_unprepare(priv->ltpi_clk); -+ return ret; -+ } ++&pwm_tach { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm9_default>; ++}; + -+ writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_STATUS); -+ writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_EN); -+ } ++&adc0 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++ aspeed,battery-sensing; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_adc7_default>; ++}; + -+ aspeed_ltpi_init_mux(priv); ++&adc1 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++ aspeed,battery-sensing; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_adc15_default>; ++}; + -+ platform_set_drvdata(pdev, priv); -+ if (np) -+ of_platform_populate(np, NULL, lookup, priv->dev); ++&pinctrl1 { ++ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { ++ pins = "U25"; ++ power-source = <1800>; ++ }; + -+ return 0; -+} ++ pinctrl_i3c0_driving: i3c0-driving { ++ pins = "U25", "U26"; ++ drive-strength = <2>; ++ }; + -+static void aspeed_ltpi_remove(struct platform_device *pdev) -+{ -+ struct aspeed_ltpi_priv *priv; ++ pinctrl_i3c1_driving: i3c1-driving { ++ pins = "Y26", "AA24"; ++ drive-strength = <2>; ++ }; + -+ priv = platform_get_drvdata(pdev); -+ reset_control_assert(priv->ltpi_rst); -+ clk_disable_unprepare(priv->ltpi_phyclk); -+ clk_disable_unprepare(priv->ltpi_clk); -+} ++ pinctrl_i3c2_driving: i3c2-driving { ++ pins = "R25", "AA26"; ++ drive-strength = <2>; ++ }; + -+static const struct of_device_id aspeed_ltpi_of_match[] = { -+ { .compatible = "aspeed-ltpi", .data = (const void *)AST2700,}, -+ { .compatible = "aspeed-ast1700-ltpi", .data = (const void *)AST1700,}, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_ltpi_of_match); ++ pinctrl_i3c3_driving: i3c3-driving { ++ pins = "R26", "Y25"; ++ drive-strength = <2>; ++ }; + -+static struct platform_driver aspeed_ltpi_driver = { -+ .probe = aspeed_ltpi_probe, -+ .remove = aspeed_ltpi_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_ltpi_of_match, -+ }, ++ pinctrl_rgmii0_driving: rgmii0-driving { ++ pins = "C20", "C19", "A8", "R14", "A7", "P14", ++ "D20", "A6", "B6", "N14", "B7", "B8"; ++ drive-strength = <1>; ++ }; +}; + -+module_platform_driver(aspeed_ltpi_driver); -+ -+MODULE_DESCRIPTION("LVDS Tunneling Protocol and Interface Bus Driver"); -+MODULE_AUTHOR("Dylan Hung "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig ---- a/drivers/char/hw_random/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/char/hw_random/Kconfig 2025-12-23 10:16:09.603225801 +0000 -@@ -587,6 +587,21 @@ - - If unsure, say Y. - -+config HW_RANDOM_ASPEED -+ tristate "Aspeed Random Number Generator support" -+ depends on ARCH_ASPEED -+ default HW_RANDOM -+ help -+ This driver provides kernel-side support for the Random Number -+ Generator hardware found on Aspeed ast2600/ast2700 devices. ++&i3c0 { ++ /* BMC_HPM_I3C_I2C_14, If AST1060 I3C_BMC_PFR_SCM_SEL(GPION4)=0 and I3C_SCM_EN(GPION5)=0 */ ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ To compile this driver as a module, choose M here: the -+ module will be called aspeed-rng. ++&i3c1 { ++ /* BMC_I2C_I3C1_SCL1 */ ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ If unsure, say Y. ++&i3c2 { ++ /* BMC_I2C_I3C2_SCL2 */ ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+source "drivers/char/hw_random/dwc/Kconfig" ++&i3c3 { ++ /* I3C_DBG_SCM */ ++ initial-role = "primary"; ++ status = "okay"; ++}; + - endif # HW_RANDOM - - config UML_RANDOM -diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile ---- a/drivers/char/hw_random/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/char/hw_random/Makefile 2025-12-23 10:16:13.771155906 +0000 -@@ -50,3 +50,5 @@ - obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o - obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o - obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o -+obj-$(CONFIG_HW_RANDOM_ASPEED) += aspeed-rng.o -+obj-$(CONFIG_HW_RANDOM_DWC) += dwc/ -diff --git a/drivers/char/hw_random/aspeed-rng.c b/drivers/char/hw_random/aspeed-rng.c ---- a/drivers/char/hw_random/aspeed-rng.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/aspeed-rng.c 2025-12-23 10:16:21.099033088 +0000 -@@ -0,0 +1,134 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) ASPEED Technology Inc. -+ */ ++/* AST2700 i3c4 -> AST1060 i3c2 for MCTP over I3C. */ ++&i3c4 { ++ /* I3C_PFR_BMC */ ++ initial-role = "target"; ++ pid = <0x000007ec 0x06000000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++&i3c5 { ++ /* I3C_MNG_BMC_SCM */ ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+#define TRNG_CTL 0x00 -+#define TRNG_EN 0x0 -+#define TRNG_MODE 0x04 -+#define TRNG_RDY 0x1f -+#define TRNG_ODATA 0x04 ++&i3c6 { ++ /* I3C_SPD_SCM */ ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+struct aspeed_trng { -+ u32 ver; -+ void __iomem *base; -+ struct hwrng rng; -+ unsigned int present: 1; -+ ktime_t period; -+ struct hrtimer timer; -+ struct completion completion; ++/* Enable UART2 and UART9 for obmc-console. */ ++&uart2 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; +}; + -+static int aspeed_trng_read(struct hwrng *rng, void *buf, size_t max, -+ bool wait) -+{ -+ struct aspeed_trng *priv = container_of(rng, struct aspeed_trng, rng); -+ u32 *data = buf; -+ size_t read = 0; -+ int timeout = max / 4 + 1; ++&uart9 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ while (read < max) { -+ if (!(readl(priv->base + TRNG_CTL) & (1 << TRNG_RDY))) { -+ if (wait) { -+ if (timeout-- == 0) -+ return read; -+ } else { -+ return 0; -+ } -+ } else { -+ *data = readl(priv->base + TRNG_ODATA); -+ data++; -+ read += 4; -+ } -+ } ++/* Enable UART7 and UART10 for obmc-console. */ ++&uart7 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ return read; -+} ++&uart10 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+static void aspeed_trng_enable(struct aspeed_trng *priv) -+{ -+ u32 ctl; ++/* UART3, UART13 and UART14 will be tunnelded to LTPI UART channels. */ ++&uart3 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ ctl = readl(priv->base + TRNG_CTL); -+ ctl = ctl & ~(1 << TRNG_EN); /* enable rng */ -+ ctl = ctl | (3 << TRNG_MODE); /* select mode */ ++&uart13 { ++ status = "okay"; ++}; + -+ writel(ctl, priv->base + TRNG_CTL); -+} ++&uart14 { ++ status = "okay"; ++}; + -+static void aspeed_trng_disable(struct aspeed_trng *priv) -+{ -+ writel(1, priv->base + TRNG_CTL); -+} ++&uart12 { ++ status = "okay"; ++}; + -+static int aspeed_trng_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct aspeed_trng *priv; -+ struct resource *res; -+ int ret; ++&fmc { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_fwspi_quad_default>; ++ pinctrl-names = "default"; + -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "bmc"; ++ spi-max-frequency = <12500000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ u-boot@0 { ++ reg = <0x0 0x400000>; // 4MB ++ label = "u-boot"; ++ }; ++ u-boot-env@400000 { ++ reg = <0x400000 0x20000>; // 128KB ++ label = "u-boot-env"; ++ }; ++ kernel@420000 { ++ reg = <0x420000 0x900000>; // 9MB ++ label = "kernel"; ++ }; ++ rofs@d20000 { ++ reg = <0xd20000 0x24a0000>; // 36.625MB ++ label = "rofs"; ++ }; ++ rwfs@31c0000 { ++ reg = <0x31c0000 0xE40000>; // 14.25MB ++ label = "rwfs"; ++ }; ++ pfm@4000000 { ++ reg = <0x4000000 0x20000>; // 128KB ++ label = "pfm"; ++ }; ++ reserved-1@4020000 { ++ reg = <0x4020000 0x200000>; // 128KB ++ label = "reserved-1"; ++ }; ++ rc-image@4220000 { ++ reg = <0x4220000 0x3de0000>; // 63360KB ++ label = "rc-image"; ++ }; ++ image-stg@8000000 { ++ reg = <0x8000000 0x3de0000>; // 63360KB ++ label = "img-stg"; ++ }; ++ pfr-stg@bde0000 { ++ reg = <0xbde0000 0x100000>; // 1024KB ++ label = "pfr-stg"; ++ }; ++ cpld-stg@bee0000 { ++ reg = <0xbee0000 0x400000>; // 4096KB ++ label = "cpld-stg"; ++ }; ++ afm-stg@c2e0000 { ++ reg = <0xc2e0000 0x20000>; // 128KB ++ label = "afm-stg"; ++ }; ++ afm-rc@c300000 { ++ reg = <0xc300000 0x20000>; // 128KB ++ label = "afm-rc"; ++ }; ++ reserved-2@c320000 { ++ reg = <0xc320000 0x3ce0000>; // 62336KB ++ label = "reserved-2"; ++ }; ++ }; ++ }; ++}; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ priv->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(priv->base)) -+ return PTR_ERR(priv->base); ++&spi0 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; ++ pinctrl-names = "default"; + -+ priv->rng.name = pdev->name; -+ priv->rng.quality = 900; -+ priv->rng.read = aspeed_trng_read; ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi0:0"; ++ spi-max-frequency = <12500000>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <1>; ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi0_pch_bios@0 { ++ reg = <0x0 0x3fe0000>; ++ label = "spi0_pch_reserved"; ++ }; ++ spi0_pch_pfm@3fe0000 { ++ reg = <0x3fe0000 0x20000>; ++ label = "spi0_pch_pfm"; ++ }; ++ spi0_pch_stg@4000000 { ++ reg = <0x4000000 0x2000000>; ++ label = "spi0_pch_stg"; ++ }; ++ spi0_pch_rc@6000000 { ++ reg = <0x6000000 0x2000000>; ++ label = "spi0_pch_rc"; ++ }; ++ }; ++ }; + -+ aspeed_trng_enable(priv); ++ flash@1 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi0:1"; ++ spi-max-frequency = <12500000>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <1>; ++ }; ++}; + -+ ret = devm_hwrng_register(&pdev->dev, &priv->rng); -+ if (ret) -+ return ret; ++&spi1 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; ++ pinctrl-names = "default"; + -+ platform_set_drvdata(pdev, priv); ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi1:0"; ++ spi-max-frequency = <12500000>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <1>; ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; + -+ dev_info(dev, "Aspeed Hardware RNG successfully registered\n"); ++ spi1_pch_reserved@0 { ++ reg = <0x0 0x7f0000>; ++ label = "spi1_pch_reserved"; ++ }; + -+ return 0; -+} ++ spi1_pch_stg@7f0000 { ++ reg = <0x7f0000 0x1400000>; ++ label = "spi1_pch_stg"; ++ }; + -+static void aspeed_trng_remove(struct platform_device *pdev) -+{ -+ struct aspeed_trng *priv = platform_get_drvdata(pdev); ++ spi1_pch_rc@1bf0000 { ++ reg = <0x1bf0000 0x1400000>; ++ label = "spi1_pch_rc"; ++ }; + -+ aspeed_trng_disable(priv); -+} ++ spi1_pch_pfm@2ff0000 { ++ reg = <0x2ff0000 0x10000>; ++ label = "spi1_pch_pfm"; ++ }; + -+static const struct of_device_id aspeed_trng_dt_ids[] = { -+ { .compatible = "aspeed,ast2600-trng" }, -+ { .compatible = "aspeed,ast2700-trng" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_trng_dt_ids); ++ spi1_pch_bios@3000000 { ++ reg = <0x3000000 0x1000000>; ++ label = "spi1_pch_bios"; ++ }; ++ }; ++ }; + -+static struct platform_driver aspeed_trng_driver = { -+ .probe = aspeed_trng_probe, -+ .remove = aspeed_trng_remove, -+ .driver = { -+ .name = "aspeed-trng", -+ .of_match_table = aspeed_trng_dt_ids, -+ }, ++ flash@1 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi1:1"; ++ spi-max-frequency = <12500000>; ++ spi-tx-bus-width = <1>; ++ spi-rx-bus-width = <1>; ++ }; +}; + -+module_platform_driver(aspeed_trng_driver); ++<pi0 { ++ status = "okay"; ++}; + -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Neal Liu "); -+MODULE_DESCRIPTION("Aspeed true random number generator driver"); -diff --git a/drivers/char/hw_random/dwc/Kconfig b/drivers/char/hw_random/dwc/Kconfig ---- a/drivers/char/hw_random/dwc/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/Kconfig 2025-12-23 10:16:19.523059502 +0000 -@@ -0,0 +1,18 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# DWC Hardware Random Number Generator (RNG) configuration -+# ++<pi1 { ++ /* Do not tunnel I2C10 to the HPM */ ++ i2c-tunneling = <0x2f>; ++ status = "okay"; ++}; + -+config HW_RANDOM_DWC -+ tristate "DesignWare Cores HW Random Number Generator support" -+ depends on HW_RANDOM -+ depends on ARCH_ASPEED || COMPILE_TEST -+ help -+ This driver provides kernel-side support for the DWC -+ Random Number Generator hardware found on Aspeed SoCs. ++/* The LTPI GPIO table is defined in Chapter 6 of the AST2700 LTPI Design Guide v10.pdf. */ ++/* line 0:BMC_GPI0(LTPI0_INL16), 1:BMC_GPO0(LTPI0_ONL16), 2:BMC_GPI1(LTPI0_INL17), 3:BMC_GPO1(LTPI0_ONL17), etc... */ ++/* BMC_GPI[63:0] = LTPI0_INL[79:16], BMC_GPO[63:0] = LTPI0_ONL[79:16] */ ++/* BMC_GPI[71:64] = LTPI0_ILL[11:4], BMC_GPO[71:64] = LTPI0_OLL[11:4] */ ++/* BMC_GPI[111:72] = LTPI0_INL[127:88],BMC_GPO[111:72] = LTPI0_ONL[127:88] */ ++<pi0_gpio { ++ status = "okay"; ++ gpio-line-names = ++ /*00-07*/ "","","","","","","","", ++ /*08-15*/ "","","","","","","","", ++ /*16-23*/ "","FM_CPU_FBRK_DEBUG_N","","FM_BMC_TRUST_N","","FM_RST_BTN_OUT_CPU0_PLD_N_OE","","FM_PWR_BTN_OUT_CPU0_N", ++ /*24-31*/ "","FM_BMC_ONCTL_N","","","","","","", ++ /*32-39*/ "","BIOS_POST_CODE_LED_0","","BIOS_POST_CODE_LED_1","","BIOS_POST_CODE_LED_2","","BIOS_POST_CODE_LED_3", ++ /*40-47*/ "FP_ID_BTN_N","BIOS_POST_CODE_LED_4","FP_RST_BTN_N","BIOS_POST_CODE_LED_5","","BIOS_POST_CODE_LED_6","","BIOS_POST_CODE_LED_7", ++ /*48-55*/ "","A_P3V_BAT_SCALED_EN","","FM_TPM_EN_PULSE","","FM_SKT0_FAULT_LED","","FM_SKT1_FAULT_LED", ++ /*56-63*/ "","","","","","RST_BMC_SMB_PCIE_MUX_N","","SURPRISE_RESET", ++ /*64-71*/ "PWRGD_S0_PWROK_CPU0","","","","","","","", ++ /*72-79*/ "","","","","","","","", ++ /*80-87*/ "","","","","","","","", ++ /*88-95*/ "","","","","","","","", ++ /*96-103*/ "","","","","","","","", ++ /*104-111*/ "","","","","","","","", ++ /*112-119*/ "","","","","","","","", ++ /*120-127*/ "","","","","","","","", ++ /*128-135*/ "","","","","","","","", ++ /*136-143*/ "","","","","","","","", ++ /*144-151*/ "","","","","","","","", ++ /*152-159*/ "","","","","","","","", ++ /*160-167*/ "","","","","","","","", ++ /*168-175*/ "","","","","","","","", ++ /*176-183*/ "","","","","","","","", ++ /*184-191*/ "","","","","","","","", ++ /*192-199*/ "","","","","","","","", ++ /*200-207*/ "","","","","","","","", ++ /*208-215*/ "","","","","","","","", ++ /*216-223*/ "","","","","","","",""; + -+ To compile this driver as a module, choose M here. the -+ module will be called dwc-rng. ++ gpio_17 { ++ gpio-hog; ++ gpios = <17 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FM_CPU_FBRK_DEBUG_N"; ++ }; ++ gpio_19 { ++ gpio-hog; ++ gpios = <19 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FM_BMC_TRUST_N"; ++ }; ++ gpio_25 { ++ gpio-hog; ++ gpios = <25 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "FM_BMC_ONCTL_N"; ++ }; ++ gpio_53 { ++ gpio-hog; ++ gpios = <53 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "FM_SKT0_FAULT_LED"; ++ }; ++ gpio_61 { ++ gpio-hog; ++ gpios = <61 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "RST_BMC_SMB_PCIE_MUX_N"; ++ }; ++ gpio_63 { ++ gpio-hog; ++ gpios = <63 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "SURPRISE_RESET"; ++ }; ++}; + -+ If unsure, say Y. ++&peci0 { ++ status = "okay"; ++}; + -diff --git a/drivers/char/hw_random/dwc/Makefile b/drivers/char/hw_random/dwc/Makefile ---- a/drivers/char/hw_random/dwc/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/Makefile 2025-12-23 10:16:19.523059502 +0000 -@@ -0,0 +1,22 @@ -+# SPDX-License-Identifier: GPL-2.0 ++&chassis { ++ status = "okay"; ++}; + -+ccflags-y := -I $(srctree)/drivers/char/hw_random/dwc/src/trng/include \ -+ -I $(srctree)/drivers/char/hw_random/dwc/src/pdu/linux/include -+ -+obj-$(CONFIG_HW_RANDOM_DWC) += elppdu.o -+elppdu-objs := src/pdu/linux/kernel/pdu.o \ -+ src/pdu/common/pdu/pdu_dev32.o \ -+ -+obj-$(CONFIG_HW_RANDOM_DWC) += elpmem.o -+elpmem-objs := src/pdu/linux/kernel/spacc_mem.o \ -+ -+obj-$(CONFIG_HW_RANDOM_DWC) += nisttrng.o -+nisttrng-objs := src/trng/kernel/nist_trng.o \ -+ src/trng/trng/nist_trng.o \ -+ src/trng/trng/nist_trng_private.o \ -+ -+clean: -+ @find \( -name '*.o' \ -+ -o -name '*.a' \ -+ -o -name '*.order' \ -+ \) -type f -print | xargs rm -rvf -diff --git a/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h b/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h ---- a/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,96 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++&mdio0 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+#ifndef SYNPDU_ERROR_H_ -+#define SYNPDU_ERROR_H_ ++ ethphy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; + -+/* -+ * Common error definitions. Be sure to update pdu_error_code when changing -+ * anything in this list. -+ */ ++&mac0 { ++ status = "okay"; + -+#define CRYPTO_OK (0) -+#define CRYPTO_FAILED (-1) -+#define CRYPTO_INPROGRESS (-2) -+#define CRYPTO_INVALID_HANDLE (-3) -+#define CRYPTO_INVALID_CONTEXT (-4) -+#define CRYPTO_INVALID_SIZE (-5) -+#define CRYPTO_NOT_INITIALIZED (-6) -+#define CRYPTO_NO_MEM (-7) -+#define CRYPTO_INVALID_ALG (-8) -+#define CRYPTO_INVALID_KEY_SIZE (-9) -+#define CRYPTO_INVALID_ARGUMENT (-10) -+#define CRYPTO_MODULE_DISABLED (-11) -+#define CRYPTO_NOT_IMPLEMENTED (-12) -+#define CRYPTO_INVALID_BLOCK_ALIGNMENT (-13) -+#define CRYPTO_INVALID_MODE (-14) -+#define CRYPTO_INVALID_KEY (-15) -+#define CRYPTO_AUTHENTICATION_FAILED (-16) -+#define CRYPTO_INVALID_IV_SIZE (-17) -+#define CRYPTO_MEMORY_ERROR (-18) -+#define CRYPTO_LAST_ERROR (-19) -+#define CRYPTO_HALTED (-20) -+#define CRYPTO_TIMEOUT (-21) -+#define CRYPTO_SRM_FAILED (-22) -+#define CRYPTO_COMMON_ERROR_MAX (-100) -+#define CRYPTO_INVALID_ICV_KEY_SIZE (-100) -+#define CRYPTO_INVALID_PARAMETER_SIZE (-101) -+#define CRYPTO_SEQUENCE_OVERFLOW (-102) -+#define CRYPTO_DISABLED (-103) -+#define CRYPTO_INVALID_VERSION (-104) -+#define CRYPTO_FATAL (-105) -+#define CRYPTO_INVALID_PAD (-106) -+#define CRYPTO_FIFO_FULL (-107) -+#define CRYPTO_INVALID_SEQUENCE (-108) -+#define CRYPTO_INVALID_FIRMWARE (-109) -+#define CRYPTO_NOT_FOUND (-110) -+#define CRYPTO_CMD_FIFO_INACTIVE (-111) -+#define CRYPTO_INVALID_PROTOCOL (-112) -+#define CRYPTO_REPLAY (-113) -+#define CRYPTO_NOT_INSTANTIATED (-114) -+#define CRYPTO_RESEED_REQUIRED (-115) ++ phy-mode = "rgmii-id"; ++ phy-handle = <ðphy0>; + -+#endif -diff --git a/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c b/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c ---- a/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,165 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; ++}; + -+#include "elppdu.h" ++&jtag1 { ++ status = "okay"; ++}; + -+void pdu_to_dev32(void *addr_, u32 *src, unsigned long nword) -+{ -+ unsigned char *addr = addr_; ++&gpio1 { ++ pinctrl-0 = <&pinctrl_i3c0_3_hv_voltage ++ &pinctrl_i3c0_driving &pinctrl_i3c1_driving ++ &pinctrl_i3c2_driving &pinctrl_i3c3_driving>; ++ pinctrl-names = "default"; + -+ while (nword--) { -+ pdu_io_write32(addr, *src++); -+ addr += 4; -+ } -+} -+EXPORT_SYMBOL(pdu_to_dev32); ++ gpio-line-names = ++ /*A0-A7*/ "","","","","","","","", ++ /*B0-B7*/ "","","","","","","","", ++ /*C0-C7*/ "","","","","","","","", ++ /*D0-D7*/ "","","","","","","","", ++ /*E0-E7*/ "","","","","FP_LED_STATUS_GREEN_CPLD_N","FP_LED_STATUS_AMBER_CPLD_N","","", ++ /*F0-F7*/ "","","","","","","","", ++ /*G0-G7*/ "","","","","","","","", ++ /*H0-H7*/ "","","","","","","","", ++ /*I0-I7*/ "","","","","","","","", ++ /*J0-J7*/ "","","","","","","","", ++ /*K0-K7*/ "","","","","","","","", ++ /*L0-L7*/ "","","","","","","","", ++ /*M0-M7*/ "","","","","","","","", ++ /*N0-N7*/ "","","","","","","","", ++ /*O0-O7*/ "","","","","","","","", ++ /*P0-P7*/ "","","","","","","","", ++ /*Q0-Q7*/ "","","","","","","","", ++ /*R0-R7*/ "","","","","","","","", ++ /*S0-S7*/ "","","","","","","","", ++ /*T0-T7*/ "","","","","","","","", ++ /*U0-U7*/ "","","","","","SCM_PHY_RST","","", ++ /*V0-V7*/ "","","","","","","","", ++ /*W0-W7*/ "","","","","","","","", ++ /*X0-X7*/ "","","","","","","","", ++ /*Y0-Y7*/ "","","","","IRQ_PMBUS1_ALERT_LVC3_N","FM_NVME_LVC3_ALERT_N","","", ++ /*Z0-Z7*/ "","","FM_NODE_ID0_N","FM_NODE_ID1_N","","PWRGD_AUX_PWRGD_PFR_CPU0","PWRGD_AUX_PWRGD_PFR_CPU1","", ++ /*AA0-AA7*/ "BMC_BOOT_DONE","","","","","","","", ++ /*AB0-AB7*/ "","","","","","","","", ++ /*AC0-AC7*/ "","","","","","","","", ++ /*AD0-AD7*/ "","","","","","","","", ++ /*AE0-AE7*/ "","","","","","","",""; ++}; + -+void pdu_from_dev32(u32 *dst, void *addr_, unsigned long nword) -+{ -+ unsigned char *addr = addr_; ++/* AST2700 A1 support SGPIO slave to 72*2 pins. */ ++/* The SGPIO slave table is defined in Chapter 7 of the AST2700 LTPI Design Guide v10.pdf. */ ++/* line 0:BMC_SGPI0(SCM_GPI0), 1:BMC_SGPO0(SCM_GPO0), 2:BMC_SGPI1(SCM_GPI1), 3:BMC_SGPO1(SCM_GPO1), etc... */ ++/* line 32:BMC_SGPI16(LTPI0_INL80), 33:BMC_SGPO16(LTPI0_ONL80), 34:LTPI0_INL81, 35:LTPI0_ONL81, etc... */ ++/* BMC_SGPI[15:0] = SCM_GPI0[15:0], BMC_SGPO[15:0] = BMC_SGPO0[15:0] */ ++/* BMC_SGPI[23:16] = LTPI0_INL[87:80], BMC_SGPO[23:16] = LTPI0_ONL[87:80] */ ++/* BMC_SGPI[31:24] = LTPI1_INL[87:80], BMC_SGPO[31:24] = LTPI1_ONL[87:80] */ ++/* BMC_SGPI[47:32] = LTPI0_INL[15:0], BMC_SGPO[47:32] = LTPI0_ONL[15:0] */ ++/* BMC_SGPI[63:48] = LTPI1_INL[15:0], BMC_SGPO[63:48] = LTPI1_ONL[15:0] */ ++/* BMC_SGPI[71:64] = SREG_GPO[7:0], BMC_SGPO[71:64] = SREG_GPI[7:0] */ ++/* The designe guide only define SCM_GPO9(FP_PWR_BTN_PFR_N) for PFR output pin. */ ++/* We use AST2700 SGPIOS line 18 (FP_PWR_BTN_PFR_N_BMC_IN) for x86-power-control power button input. */ ++&sgpios { ++ status = "okay"; ++ gpio-line-names = ++ /*00-07*/ "","","","","","","","", ++ /*08-15*/ "","","","","","","","", ++ /*16-23*/ "","","FP_PWR_BTN_PFR_N_BMC_IN","","","","","", ++ /*24-31*/ "","","","","","","","", ++ /*32-39*/ "","","","","","","","", ++ /*40-47*/ "","","","","","","","", ++ /*48-55*/ "","","","","","","","", ++ /*56-63*/ "","","","","","","","", ++ /*64-71*/ "","","","","","","","", ++ /*72-79*/ "","","","","","","","", ++ /*80-87*/ "","","","","","","","", ++ /*88-95*/ "","","","","","","","", ++ /*96-103*/ "","","","","","","","", ++ /*104-111*/ "","","","","","","","", ++ /*112-119*/ "","","","","","","","", ++ /*120-127*/ "","","","","","","","", ++ /*128-135*/ "","","","","","","","", ++ /*136-143*/ "","","","","","","",""; ++}; + -+ while (nword--) { -+ *dst++ = pdu_io_read32(addr); -+ addr += 4; -+ } -+} -+EXPORT_SYMBOL(pdu_from_dev32); ++&espi0 { ++ status = "okay"; ++ perif-dma-mode; ++ perif-mmbi-enable; ++ perif-mmbi-src-addr = <0x0 0xa8000000>; ++ perif-mmbi-tgt-memory = <&espi0_mmbi_memory>; ++ perif-mmbi-instance-num = <0x1>; ++ perif-mcyc-enable; ++ perif-mcyc-src-addr = <0x0 0x98000000>; ++ perif-mcyc-size = <0x0 0x10000>; ++ vw-pltrst-monitor; ++ oob-dma-mode; ++ flash-dma-mode; ++}; + -+void pdu_to_dev32_big(void *addr_, const unsigned char *src, -+ unsigned long nword) -+{ -+ unsigned char *addr = addr_; -+ unsigned long v; ++#if 0 //eSPI1 and SD are multi-functional pin, SD default on ++&espi1 { ++ status = "okay"; ++ perif-dma-mode; ++ perif-mmbi-enable; ++ perif-mmbi-src-addr = <0x0 0xa8000000>; ++ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; ++ perif-mmbi-instance-num = <0x1>; ++ perif-mcyc-enable; ++ perif-mcyc-src-addr = <0x0 0x98000000>; ++ perif-mcyc-size = <0x0 0x10000>; ++ vw-pltrst-monitor; ++ oob-dma-mode; ++ flash-dma-mode; ++}; ++#endif + -+ while (nword--) { -+ v = 0; -+ v = (v << 8) | ((unsigned long)*src++); -+ v = (v << 8) | ((unsigned long)*src++); -+ v = (v << 8) | ((unsigned long)*src++); -+ v = (v << 8) | ((unsigned long)*src++); -+ pdu_io_write32(addr, v); -+ addr += 4; -+ } -+} -+EXPORT_SYMBOL(pdu_to_dev32_big); -+ -+void pdu_from_dev32_big(unsigned char *dst, void *addr_, unsigned long nword) -+{ -+ unsigned char *addr = addr_; -+ unsigned long v; -+ -+ while (nword--) { -+ v = pdu_io_read32(addr); -+ addr += 4; -+ *dst++ = (v >> 24) & 0xFF; -+ v <<= 8; -+ *dst++ = (v >> 24) & 0xFF; -+ v <<= 8; -+ *dst++ = (v >> 24) & 0xFF; -+ v <<= 8; -+ *dst++ = (v >> 24) & 0xFF; -+ v <<= 8; -+ } -+} -+EXPORT_SYMBOL(pdu_from_dev32_big); ++&lpc0_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0xca0>; ++ kcs-channel = <0>; ++}; + -+void pdu_to_dev32_little(void *addr_, const unsigned char *src, -+ unsigned long nword) -+{ -+ unsigned char *addr = addr_; -+ unsigned long v; ++&lpc0_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0xca8>; ++ kcs-channel = <1>; ++}; + -+ while (nword--) { -+ v = 0; -+ v = (v >> 8) | ((unsigned long)*src++ << 24UL); -+ v = (v >> 8) | ((unsigned long)*src++ << 24UL); -+ v = (v >> 8) | ((unsigned long)*src++ << 24UL); -+ v = (v >> 8) | ((unsigned long)*src++ << 24UL); -+ pdu_io_write32(addr, v); -+ addr += 4; -+ } -+} -+EXPORT_SYMBOL(pdu_to_dev32_little); ++&lpc0_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0xca2>; ++ kcs-channel = <2>; ++}; + -+void pdu_from_dev32_little(unsigned char *dst, void *addr_, unsigned long nword) -+{ -+ unsigned char *addr = addr_; -+ unsigned long v; ++&lpc0_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0xca4>; ++ kcs-channel = <3>; ++}; + -+ while (nword--) { -+ v = pdu_io_read32(addr); -+ addr += 4; -+ *dst++ = v & 0xFF; -+ v >>= 8; -+ *dst++ = v & 0xFF; -+ v >>= 8; -+ *dst++ = v & 0xFF; -+ v >>= 8; -+ *dst++ = v & 0xFF; -+ v >>= 8; -+ } -+} -+EXPORT_SYMBOL(pdu_from_dev32_little); ++&lpc0_ibt { ++ status = "okay"; ++}; + -+void pdu_to_dev32_s(void *addr, const unsigned char *src, unsigned long nword, -+ int endian) -+{ -+ if (endian) -+ pdu_to_dev32_big(addr, src, nword); -+ else -+ pdu_to_dev32_little(addr, src, nword); -+} -+EXPORT_SYMBOL(pdu_to_dev32_s); ++&lpc0_mbox { ++ status = "okay"; ++}; + -+void pdu_from_dev32_s(unsigned char *dst, void *addr, unsigned long nword, -+ int endian) -+{ -+ if (endian) -+ pdu_from_dev32_big(dst, addr, nword); -+ else -+ pdu_from_dev32_little(dst, addr, nword); -+} -+EXPORT_SYMBOL(pdu_from_dev32_s); -diff --git a/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h b/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h ---- a/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,125 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++&lpc0_snoop { ++ status = "okay"; ++ snoop-ports = <0x80>, <0x81>; ++}; + -+#ifndef SYNPDU_H_ -+#define SYNPDU_H_ ++&lpc0_uart_routing { ++ status = "okay"; ++}; + -+/* Platform Specific */ -+#include /* printk() */ -+#include /* size_t */ -+#include /* memcpy()/etc */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++&lpc1_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0xca0>; ++ kcs-channel = <4>; ++}; + -+#ifndef PDU_BASE_ADDR -+#define PDU_BASE_ADDR 0x14c3b000 -+#endif ++&lpc1_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0xca8>; ++ kcs-channel = <5>; ++}; + -+#ifndef PDU_BASE_IRQ -+#define PDU_BASE_IRQ 91 -+#endif ++&lpc1_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0xca2>; ++ kcs-channel = <6>; ++}; + -+#define PDU_SINGLE_CORE 1 -+#define PDU_SINGLE_NIST_TRNG 1 ++&lpc1_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0xca4>; ++ kcs-channel = <7>; ++}; + -+#if 1 -+#define SYNHW_PRINT printk -+#else -+#define SYNHW_PRINT(...) -+#endif ++&lpc1_ibt { ++ status = "okay"; ++}; + -+#define CPU_YIELD -+#define SYNHW_MEMCPY memcpy ++&lpc1_mbox { ++ status = "okay"; ++}; + -+// Debug modifier for printing, in linux adding KERN_DEBUG makes the output only show up in debug logs (avoids /var/log/messages) -+#define SYNHW_PRINT_DEBUG KERN_DEBUG ++&lpc1_snoop { ++ status = "okay"; ++ snoop-ports = <0x80>, <0x81>; ++}; + -+// Locking -+#define PDU_LOCK_TYPE spinlock_t -+#define PDU_INIT_LOCK(lock) spin_lock_init(lock) ++&lpc1_uart_routing { ++ status = "okay"; ++}; + -+// these are for IRQ contexts -+#define PDU_LOCK(lock, flags) spin_lock_irqsave(lock, flags) -+#define PDU_UNLOCK(lock, flags) spin_unlock_irqrestore(lock, flags) ++&video0 { ++ status = "okay"; ++ memory-region = <&video_engine_memory0>; ++}; + -+// these are for bottom half BH contexts -+#define PDU_LOCK_TYPE_BH struct mutex -+#define PDU_INIT_LOCK_BH(lock) mutex_init(lock) -+#define PDU_LOCK_BH(lock) mutex_lock(lock) -+#define PDU_UNLOCK_BH(lock) mutex_unlock(lock) ++&video1 { ++ status = "okay"; ++ memory-region = <&video_engine_memory1>; ++}; + -+#include "../../common/include/elppdu_error.h" ++&disp_intf { ++ status = "okay"; ++}; + -+void *pdu_linux_map_regs(struct device *dev, struct resource *regs); ++&rtc { ++ status = "okay"; ++}; + -+void pdu_io_write32(void *addr, unsigned long val); -+void pdu_io_cached_write32(void *addr, unsigned long val, u32 *cache); -+unsigned long pdu_io_read32(void *addr); ++&rsss { ++ status = "okay"; ++}; + -+void pdu_to_dev32(void *addr, u32 *src, unsigned long nword); -+void pdu_from_dev32(u32 *dst, void *addr, unsigned long nword); -+void pdu_to_dev32_big(void *addr, const unsigned char *src, unsigned long nword); -+void pdu_from_dev32_big(unsigned char *dst, void *addr, unsigned long nword); -+void pdu_to_dev32_little(void *addr, const unsigned char *src, unsigned long nword); -+void pdu_from_dev32_little(unsigned char *dst, void *addr, unsigned long nword); -+void pdu_from_dev32_s(unsigned char *dst, void *addr, unsigned long nword, int endian); -+void pdu_to_dev32_s(void *addr, const unsigned char *src, unsigned long nword, int endian); ++&ecdsa { ++ status = "okay"; ++}; + -+void *pdu_malloc(unsigned long n); -+void pdu_free(void *p); ++&hace { ++ dummy-key0 = < ++ 0x89878915 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key1 = < ++ 0x89878902 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key2 = < ++ 0x2C914FA3 0x1056D87B 0xC13D6AE2 0x5E44AF98 ++ 0x0DB97321 0xCA378CF6 0x62EE115D 0x3FA74B90 ++ >; ++ dummy-key3 = < ++ 0x9E18D25C 0x6FB17A43 0x348DE520 0x1269FAC7 ++ 0xAC5503DE 0x2DB61F88 0xEF9AC074 0xB84E6731 ++ >; ++ status = "okay"; ++}; + -+int pdu_error_code(int code); ++&bmc_dev0 { ++ status = "okay"; ++ memory-region = <&bmc_dev0_memory>; ++}; + -+#endif ++&xdma0 { ++ status = "okay"; ++ memory-region = <&xdma_memory0>; ++}; + -diff --git a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c ---- a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++&pcie_vuart0 { ++ port = <0x3f8>; ++ sirq = <4>; ++ sirq-polarity = <0>; + -+#include ++ status = "okay"; ++}; + -+#include "elppdu.h" ++&pcie_vuart1 { ++ port = <0x2f8>; ++ sirq = <3>; ++ sirq-polarity = <0>; + -+static bool trace_io; -+module_param(trace_io, bool, 0600); -+MODULE_PARM_DESC(trace_io, "Trace MMIO reads/writes"); ++ status = "okay"; ++}; + -+void *pdu_linux_map_regs(struct device *dev, struct resource *regs) -+{ -+ return devm_ioremap_resource(dev, regs); -+} -+EXPORT_SYMBOL(pdu_linux_map_regs); ++&pcie_lpc0_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0x3a0>; ++ kcs-channel = <8>; ++}; + -+void pdu_io_write32(void *addr, unsigned long val) -+{ -+ if (trace_io) -+ SYNHW_PRINT("PDU: write %.8lx -> %p\n", val, addr); ++&pcie_lpc0_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0x3a8>; ++ kcs-channel = <9>; ++}; + -+ writel(val, addr); -+} -+EXPORT_SYMBOL(pdu_io_write32); ++&pcie_lpc0_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0x3a2>; ++ kcs-channel = <10>; ++}; + -+void pdu_io_cached_write32(void *addr, unsigned long val, uint32_t *cache) -+{ -+ if (*cache == val) { -+ if (trace_io) { -+ SYNHW_PRINT("PDU: write %.8lx -> %p (cached)\n", val, -+ addr); -+ } -+ return; -+ } ++&pcie_lpc0_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0x3a4>; ++ kcs-channel = <11>; ++}; + -+ *cache = val; -+ pdu_io_write32(addr, val); -+} -+EXPORT_SYMBOL(pdu_io_cached_write32); ++&pcie_lpc0_ibt { ++ status = "okay"; ++ bt-channel = <2>; ++}; + -+unsigned long pdu_io_read32(void *addr) -+{ -+ unsigned long val; ++&bmc_dev1 { ++ status = "okay"; ++ memory-region = <&bmc_dev1_memory>; ++}; + -+ val = readl(addr); ++&xdma1 { ++ status = "okay"; ++ memory-region = <&xdma_memory1>; ++}; + -+ if (trace_io) -+ SYNHW_PRINT("PDU: read %.8lx <- %p\n", val, addr); ++&pcie_vuart2 { ++ port = <0x3f8>; ++ sirq = <4>; ++ sirq-polarity = <0>; + -+ return val; -+} -+EXPORT_SYMBOL(pdu_io_read32); ++ status = "okay"; ++}; + -+/* Platform specific memory allocation */ -+void *pdu_malloc(unsigned long n) -+{ -+ return vmalloc(n); -+} ++&pcie_vuart3 { ++ port = <0x2f8>; ++ sirq = <3>; ++ sirq-polarity = <0>; + -+void pdu_free(void *p) -+{ -+ vfree(p); -+} ++ status = "okay"; ++}; + -+/* Convert SDK error codes to corresponding kernel error codes. */ -+int pdu_error_code(int code) -+{ -+ switch (code) { -+ case CRYPTO_INPROGRESS: -+ return -EINPROGRESS; -+ case CRYPTO_INVALID_HANDLE: -+ case CRYPTO_INVALID_CONTEXT: -+ return -ENXIO; -+ case CRYPTO_NOT_INITIALIZED: -+ return -ENODATA; -+ case CRYPTO_INVALID_SIZE: -+ case CRYPTO_INVALID_ALG: -+ case CRYPTO_INVALID_KEY_SIZE: -+ case CRYPTO_INVALID_ARGUMENT: -+ case CRYPTO_INVALID_BLOCK_ALIGNMENT: -+ case CRYPTO_INVALID_MODE: -+ case CRYPTO_INVALID_KEY: -+ case CRYPTO_INVALID_IV_SIZE: -+ case CRYPTO_INVALID_ICV_KEY_SIZE: -+ case CRYPTO_INVALID_PARAMETER_SIZE: -+ case CRYPTO_REPLAY: -+ case CRYPTO_INVALID_PROTOCOL: -+ case CRYPTO_RESEED_REQUIRED: -+ return -EINVAL; -+ case CRYPTO_NOT_IMPLEMENTED: -+ case CRYPTO_MODULE_DISABLED: -+ return -ENOTSUPP; -+ case CRYPTO_NO_MEM: -+ return -ENOMEM; -+ case CRYPTO_INVALID_PAD: -+ case CRYPTO_INVALID_SEQUENCE: -+ return -EILSEQ; -+ case CRYPTO_MEMORY_ERROR: -+ return -EIO; -+ case CRYPTO_TIMEOUT: -+ return -ETIMEDOUT; -+ case CRYPTO_HALTED: -+ return -ECANCELED; -+ case CRYPTO_AUTHENTICATION_FAILED: -+ case CRYPTO_SEQUENCE_OVERFLOW: -+ case CRYPTO_INVALID_VERSION: -+ return -EPROTO; -+ case CRYPTO_FIFO_FULL: -+ return -EBUSY; -+ case CRYPTO_SRM_FAILED: -+ case CRYPTO_DISABLED: -+ case CRYPTO_LAST_ERROR: -+ return -EAGAIN; -+ case CRYPTO_FAILED: -+ case CRYPTO_FATAL: -+ return -EIO; -+ case CRYPTO_INVALID_FIRMWARE: -+ return -ENOEXEC; -+ case CRYPTO_NOT_FOUND: -+ return -ENOENT; -+ } ++&pcie_lpc1_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0x3a0>; ++ kcs-channel = <12>; ++}; + -+ /* -+ * Any unrecognized code is either success (i.e., zero) or a negative -+ * error code, which may be meaningless but at least will still be -+ * recognized as an error. -+ */ -+ return code; -+} -+EXPORT_SYMBOL(pdu_error_code); ++&pcie_lpc1_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0x3a8>; ++ kcs-channel = <13>; ++}; + -+static int __init pdu_mod_init(void) -+{ -+ return 0; -+} ++&pcie_lpc1_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0x3a2>; ++ kcs-channel = <14>; ++}; + -+static void __exit pdu_mod_exit(void) -+{ -+} ++&pcie_lpc1_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0x3a4>; ++ kcs-channel = <15>; ++}; + -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Synopsys, Inc."); -+module_init(pdu_mod_init); -+module_exit(pdu_mod_exit); -diff --git a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c ---- a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,191 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2011-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++&pcie_lpc1_ibt { ++ status = "okay"; ++ bt-channel = <3>; ++}; + -+#include -+#include -+#include -+#include -+#include -+#include ++&mctp0 { ++ status = "okay"; ++ memory-region = <&mctp0_reserved>; ++}; + -+#include "elppdu.h" ++&mctp1 { ++ status = "okay"; ++ memory-region = <&mctp1_reserved>; ++}; + -+static unsigned long vex_baseaddr = PDU_BASE_ADDR; -+module_param_named(baseaddr, vex_baseaddr, ulong, 0); -+MODULE_PARM_DESC(baseaddr, "Hardware base address (default " __stringify(PDU_BASE_ADDR) ")"); ++/* Enable i2c0~i2c4 for LTPI testing. */ ++&i2c0 { ++ /* SMB_PMBUS1_SCM */ ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+// max of 16 devices -+#define MAX_DEV 16 ++&i2c1 { ++ /* SMB_IPMB_SCL1 */ ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+static struct platform_device *devices[MAX_DEV]; -+static int dev_id; ++&i2c2 { ++ /* SMB_CPLD_SCL2 */ ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+static void register_device(const char *name, int id, -+ const struct resource *res, unsigned int num) -+{ -+ char suffix[16] = ""; -+ struct platform_device_info pdevinfo = { -+ .name = name, -+ .id = id, -+ .res = res, -+ .num_res = num, -+ .dma_mask = 0xffffffff, -+ }; ++&i2c3 { ++ /* SMB_PMBUS2_SCM */ ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ if (dev_id >= MAX_DEV) { -+ pr_err("Too many devices; increase MAX_DEV.\n"); -+ return; -+ } ++&i2c4 { ++ /* SMB_PMBUS1_SCM */ ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ devices[dev_id] = platform_device_register_full(&pdevinfo); -+ if (IS_ERR(devices[dev_id])) { -+ if (id >= 0) -+ snprintf(suffix, sizeof(suffix), ".%d", id); -+ pr_err("Failed to register %s%s\n", name, suffix); ++/* Default i2c5 is tunnelded to LTPI. */ ++/* Enable i2c5 pinctrl for testing on board LM75. */ ++&i2c5 { ++ /* SMB_TMP_BMC */ ++ status = "okay"; ++}; + -+ devices[dev_id] = NULL; -+ return; -+ } ++/* AST2700 i2c8 -> AST1060 i2c5 for PCH mailbox emulation test. */ ++&i2c8 { ++ /* SMB_PCIE_SCM */ ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ dev_id++; -+} ++&i2c9 { ++ /* SMB_HOST_BMC */ ++ status = "okay"; ++ eeprom@50 { ++ compatible = "atmel,24c04"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++}; + -+static int __init get_irq_num(unsigned int irq_num) -+{ -+ if (IS_ENABLED(CONFIG_ARCH_ZYNQ)) { -+ struct of_phandle_args args = { 0 }; ++/* AST2700 A1 i2c10 -> AST1060 i2c0 for PFR mailbox. */ ++&i2c10 { ++ /* SMB_HSBP_BMC */ ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ /* -+ * Since this driver is for non-DT use but Zynq uses DT to setup IRQs, -+ * find the GIC by searching for its DT node then manually create the -+ * IRQ mappings. -+ */ ++&i2c11 { ++ /* BMC_HPM_I3C_I2C_13 */ ++ status = "okay"; ++}; + -+ do { -+ args.np = of_find_node_with_property(args.np, -+ "interrupt-controller"); -+ if (!args.np) { -+ pr_err("cannot find IRQ controller"); -+ return -ENODEV; -+ } -+ } while (!of_device_is_compatible(args.np, "arm,cortex-a9-gic")); ++&vhuba0 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; ++}; + -+ if (irq_num < 32 || irq_num >= 96) { -+ pr_err("SPI interrupts must be in the range [32,96) on Zynq\n"); -+ return -EINVAL; -+ } ++&vhubb1 { ++ status = "okay"; ++}; + -+ args.args_count = 3; -+ args.args[0] = 0; /* SPI */ -+ args.args[1] = irq_num - 32; -+ args.args[2] = 4; /* Active high, level-sensitive */ ++&vhubc { ++ status = "okay"; ++}; + -+ irq_num = irq_create_of_mapping(&args); -+ of_node_put(args.np); -+ if (irq_num == 0) -+ return -EINVAL; -+ } ++&ehci3 { ++ status = "okay"; ++}; + -+ if (irq_num > INT_MAX) -+ return -EINVAL; ++&uhci1 { ++ status = "okay"; ++ memory-region = <&uhci1_reserved>; ++}; + -+ return irq_num; -+} ++&wdt0 { ++ status = "okay"; ++}; + -+static int __init pdu_vex_mod_init(void) -+{ -+ int irq_num = get_irq_num(PDU_BASE_IRQ); -+ struct resource res[2]; -+#ifndef PDU_SINGLE_CORE -+ void *pdu_mem; -+ int i, rc; -+#endif ++&wdt1 { ++ status = "okay"; ++}; + -+ if (irq_num >= 0) { -+ res[1] = (struct resource){ -+ .start = irq_num, -+ .end = irq_num, -+ .flags = IORESOURCE_IRQ, -+ }; -+ } else { -+ res[1] = (struct resource){ 0 }; -+ pr_err("IRQ setup failed (error %d), not using IRQs\n", -+ irq_num); -+ } ++&otp { ++ status = "okay"; ++}; + -+#ifdef PDU_SINGLE_BASIC_TRNG -+ res[0] = (struct resource){ -+ .start = vex_baseaddr, -+ .end = vex_baseaddr + 0x80 - 1, -+ .flags = IORESOURCE_MEM, ++#if 0 ++&soc0 { ++ mbox-ssp-0 { ++ compatible = "aspeed,aspeed-mbox"; ++ reg = <0x4 0x31480000 0x0 0x200000>, <0x0 0x10001000 0x0 0x1000>; ++ mboxes = <&mbox0 0>; ++ aspeed,tx-timeout = <100>; + }; -+ register_device("basic_trng", -1, res, 2); ++}; +#endif + -+#ifdef PDU_SINGLE_NIST_TRNG -+ res[0] = (struct resource){ -+ .start = vex_baseaddr, -+ .end = vex_baseaddr + 0x800 - 1, -+ .flags = IORESOURCE_MEM, ++#if 1 ++&soc0 { ++ mbox-bootmcu-1 { ++ compatible = "aspeed,aspeed-mbox"; ++ reg = <0x4 0x31880000 0x0 0x100000>, <0x4 0x31980000 0x0 0x100000>; ++ mboxes = <&mbox2 1>; ++ aspeed,tx-timeout = <10000>; + }; -+ register_device("nist_trng", -1, res, 2); ++}; +#endif +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,218 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ return 0; -+} -+module_init(pdu_vex_mod_init); -+ -+static void __exit pdu_vex_mod_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_DEV; i++) -+ platform_device_unregister(devices[i]); -+} -+module_exit(pdu_vex_mod_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Synopsys, Inc."); -diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h ---- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,63 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++/dts-v1/; + -+#ifndef NISTTRNG_H -+#define NISTTRNG_H -+ -+#include "synversion.h" -+#include "elppdu.h" -+#include "nisttrng_hw.h" -+#include "nisttrng_common.h" -+#include "nisttrng_private.h" -+ -+int nisttrng_init(struct nist_trng_state *state, u32 *base); -+int nisttrng_instantiate(struct nist_trng_state *state, int req_sec_strength, int pred_resist, void *personal_str); -+int nisttrng_uninstantiate(struct nist_trng_state *state); -+int nisttrng_reseed(struct nist_trng_state *state, int pred_resist, void *addin_str); -+int nisttrng_generate(struct nist_trng_state *state, void *random_bits, unsigned long req_num_bytes, int req_sec_strength, int pred_resist, void *addin_str); -+int nisttrng_rbc(struct nist_trng_state *state, int enable, int rbc_num, int rate, int urun_blnk); -+int nisttrng_generate_public_vtrng(struct nist_trng_state *state, void *random_bits, unsigned long req_num_bytes, int vtrng); -+#endif -diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h ---- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,144 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+// ------------------------------------------------------------------------ -+// -+// (C) COPYRIGHT 2012 - 2016 SYNOPSYS, INC. -+// ALL RIGHTS RESERVED -+// -+// (C) COPYRIGHT 2012-2016 Synopsys, Inc. -+// This Synopsys software and all associated documentation are -+// proprietary to Synopsys, Inc. and may only be used pursuant -+// to the terms and conditions of a written license agreement -+// with Synopsys, Inc. All other use, reproduction, modification, -+// or distribution of the Synopsys software or the associated -+// documentation is strictly prohibited. -+// -+// ------------------------------------------------------------------------ ++#include "ast2700a1-dcscm_ast1700a1-evb.dts" ++#include "aspeed-ltpi1.dtsi" + -+#ifndef NISTTRNG_COMMON_H -+#define NISTTRNG_COMMON_H ++/ { ++ model = "AST2700A1-DCSCM_AST1700A1-EVB-DUAL"; + -+#define NIST_TRNG_RETRY_MAX 5000000UL ++ ltpi1-iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <<pi1_adc0 0>, <<pi1_adc0 1>, <<pi1_adc0 2>, <<pi1_adc0 3>, ++ <<pi1_adc0 4>, <<pi1_adc0 5>, <<pi1_adc0 6>, <<pi1_adc0 7>, ++ <<pi1_adc1 0>, <<pi1_adc1 1>, <<pi1_adc1 2>, <<pi1_adc1 3>, ++ <<pi1_adc1 4>, <<pi1_adc1 5>, <<pi1_adc1 6>, <<pi1_adc1 7>; ++ }; ++}; + -+#define NIST_DFLT_MAX_BITS_PER_REQ BIT(19) -+#define NIST_DFLT_MAX_REQ_PER_SEED BIT(48) ++<pi1_adc0 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++}; + -+/* Do not change the following parameters */ -+#define NIST_TRNG_DFLT_MAX_REJECTS 10 ++<pi1_adc1 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++}; + -+#define DEBUG(...) -+//#define DEBUG(...) printk(__VA_ARGS__) ++<pi1 { ++ i2c-tunneling = <0x0>; ++ status = "okay"; ++}; + -+enum nisttrng_sec_strength { -+ SEC_STRNT_AES128 = 0, -+ SEC_STRNT_AES256 = 1 ++<pi1_gpio { ++ status = "okay"; +}; + -+enum nisttrng_drbg_arch { -+ AES128 = 0, -+ AES256 = 1 ++<pi1_i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; +}; + -+enum nisttrng_current_state { -+ NIST_TRNG_STATE_INITIALIZE = 0, -+ NIST_TRNG_STATE_UNINSTANTIATE, -+ NIST_TRNG_STATE_INSTANTIATE, -+ NIST_TRNG_STATE_RESEED, -+ NIST_TRNG_STATE_GENERATE ++<pi1_i3c1 { ++ initial-role = "primary"; ++ status = "okay"; +}; + -+struct nist_trng_state { -+ u32 *base; ++<pi1_i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* Hardware features and build ID */ -+ struct { -+ struct { -+ enum nisttrng_drbg_arch drbg_arch; -+ unsigned int extra_ps_present, -+ secure_rst_state, -+ diag_level_basic_trng, -+ diag_level_stat_hlt, -+ diag_level_ns; -+ } features; -+ -+ struct { -+ unsigned int ext_enum, -+ ext_ver, -+ rel_num; -+ } corekit_rel; -+ -+ struct { -+ unsigned int core_type, -+ bg8, -+ cdc_synch_depth, -+ background_noise, -+ edu_present, -+ aes_datapath, -+ aes_max_key_size, -+ personilzation_str; -+ } build_cfg0; -+ -+ struct { -+ unsigned int num_raw_noise_blks, -+ sticky_startup, -+ auto_correlation_test, -+ mono_bit_test, -+ run_test, -+ poker_test, -+ raw_ht_adap_test, -+ raw_ht_rep_test, -+ ent_src_rep_smpl_size, -+ ent_src_rep_test, -+ ent_src_rep_min_entropy; -+ } build_cfg1; -+ -+ struct { -+ unsigned int rbc2_rate_width, -+ rbc1_rate_width, -+ rbc0_rate_width, -+ public_vtrng_channels, -+ esm_channel, -+ rbc_channels, -+ fifo_depth; -+ } edu_build_cfg0; -+ } config; -+ -+ /* status */ -+ struct { -+ //nist_trng_current_state current_state; -+ enum nisttrng_current_state current_state; // old for now -+ unsigned int nonce_mode, -+ secure_mode, -+ pred_resist; -+ //nist_trng_sec_strength sec_strength; -+ enum nisttrng_sec_strength sec_strength; -+ unsigned int pad_ps_addin; -+ unsigned int alarm_code; -+ // Private VTRNG STAT, all the public trng will have the same STAT as public TRNG in terms of -+ // rnc_enabled and seed_enum -+ struct { -+ unsigned int seed_enum, -+ rnc_enabled; -+ } edu_vstat; -+ } status; -+ -+ /* reminders and alarms */ -+ struct { -+ unsigned long max_bits_per_req; -+ unsigned long long max_req_per_seed; -+ unsigned long bits_per_req_left; -+ unsigned long long req_per_seed_left; -+ } counters; ++<pi1_i3c3 { ++ initial-role = "primary"; ++ status = "okay"; +}; + -+#define nist_trng_zero_status(x) \ -+ memset(&((x)->status), 0, sizeof((x)->status)) ++<pi1_i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+#define DRBG_INSTANTIATED(cs) \ -+ ((((cs) == NIST_TRNG_STATE_INSTANTIATE) || \ -+ ((cs) == NIST_TRNG_STATE_RESEED) || \ -+ ((cs) == NIST_TRNG_STATE_GENERATE)) ? 1 : 0) ++<pi1_i3c5 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+#define REQ_SEC_STRENGTH_IS_VALID(sec_st) \ -+ ((((sec_st) > 0) && ((sec_st) <= 256)) ? 1 : 0) -+ -+#endif -diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h ---- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,457 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef NISTTRNG_HW_H -+#define NISTTRNG_HW_H ++<pi1_i3c6 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06016000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+/* HW related Parameters */ -+#define NIST_TRNG_RAND_BLK_SIZE_BITS 128 -+#define CHX_URUN_BLANK_AFTER_RESET 0x3 ++<pi1_i3c7 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+/* registers */ -+#define NIST_TRNG_REG_CTRL 0x00 -+#define NIST_TRNG_REG_MODE 0x01 -+#define NIST_TRNG_REG_SMODE 0x02 -+#define NIST_TRNG_REG_STAT 0x03 -+#define NIST_TRNG_REG_IE 0x04 -+#define NIST_TRNG_REG_ISTAT 0x05 -+#define NIST_TRNG_REG_ALARM 0x06 -+#define NIST_TRNG_REG_COREKIT_REL 0x07 -+#define NIST_TRNG_REG_FEATURES 0x08 -+#define NIST_TRNG_REG_RAND0 0x09 -+#define NIST_TRNG_REG_RAND1 0x0A -+#define NIST_TRNG_REG_RAND2 0x0B -+#define NIST_TRNG_REG_RAND3 0x0C -+#define NIST_TRNG_REG_NPA_DATA0 0x0D -+#define NIST_TRNG_REG_NPA_DATA1 0x0E -+#define NIST_TRNG_REG_NPA_DATA2 0x0F -+#define NIST_TRNG_REG_NPA_DATA3 0x10 -+#define NIST_TRNG_REG_NPA_DATA4 0x11 -+#define NIST_TRNG_REG_NPA_DATA5 0x12 -+#define NIST_TRNG_REG_NPA_DATA6 0x13 -+#define NIST_TRNG_REG_NPA_DATA7 0x14 -+#define NIST_TRNG_REG_NPA_DATA8 0x15 -+#define NIST_TRNG_REG_NPA_DATA9 0x16 -+#define NIST_TRNG_REG_NPA_DATA10 0x17 -+#define NIST_TRNG_REG_NPA_DATA11 0x18 -+#define NIST_TRNG_REG_NPA_DATA12 0x19 -+#define NIST_TRNG_REG_NPA_DATA13 0x1A -+#define NIST_TRNG_REG_NPA_DATA14 0x1B -+#define NIST_TRNG_REG_NPA_DATA15 0x1C -+#define NIST_TRNG_REG_SEED0 0x1D -+#define NIST_TRNG_REG_SEED1 0x1E -+#define NIST_TRNG_REG_SEED2 0x1F -+#define NIST_TRNG_REG_SEED3 0x20 -+#define NIST_TRNG_REG_SEED4 0x21 -+#define NIST_TRNG_REG_SEED5 0x22 -+#define NIST_TRNG_REG_SEED6 0x23 -+#define NIST_TRNG_REG_SEED7 0x24 -+#define NIST_TRNG_REG_SEED8 0x25 -+#define NIST_TRNG_REG_SEED9 0x26 -+#define NIST_TRNG_REG_SEED10 0x27 -+#define NIST_TRNG_REG_SEED11 0x28 -+#define NIST_TRNG_REG_TIME_TO_SEED 0x34 -+#define NIST_TRNG_REG_IA_RDATA 0x38 -+#define NIST_TRNG_REG_IA_WDATA 0x39 -+#define NIST_TRNG_REG_IA_ADDR 0x3A -+#define NIST_TRNG_REG_IA_CMD 0x3B -+#define NIST_TRNG_REG_BUILD_CFG0 0x3C -+#define NIST_TRNG_REG_BUILD_CFG1 0x3D -+ -+/* nist edu registers */ -+#define NIST_TRNG_EDU_RNC_CTRL 0x100 -+#define NIST_TRNG_EDU_FLUSH_CTRL 0x101 -+#define NIST_TRNG_EDU_RESEED_CNTR 0x102 -+#define NIST_TRNG_EDU_RBC_CTRL 0x104 -+#define NIST_TRNG_EDU_STAT 0x106 -+#define NIST_TRNG_EDU_IE 0x108 -+#define NIST_TRNG_EDU_ISTAT 0x109 -+#define NIST_TRNG_EDU_BUILD_CFG0 0x12C -+#define NIST_TRNG_EDU_VCTRL 0x138 -+#define NIST_TRNG_EDU_VSTAT 0x139 -+#define NIST_TRNG_EDU_VIE 0x13A -+#define NIST_TRNG_EDU_VISTAT 0x13B -+#define NIST_TRNG_EDU_VRAND_0 0x13C -+#define NIST_TRNG_EDU_VRAND_1 0x13D -+#define NIST_TRNG_EDU_VRAND_2 0x13E -+#define NIST_TRNG_EDU_VRAND_3 0x13F -+ -+/* edu vtrng registers */ -+#define NIST_TRNG_EDU_VTRNG_VCTRL0 0x180 -+#define NIST_TRNG_EDU_VTRNG_VSTAT0 0x181 -+#define NIST_TRNG_EDU_VTRNG_VIE0 0x182 -+#define NIST_TRNG_EDU_VTRNG_VISTAT0 0x183 -+#define NIST_TRNG_EDU_VTRNG_VRAND0_0 0x184 -+#define NIST_TRNG_EDU_VTRNG_VRAND0_1 0x185 -+#define NIST_TRNG_EDU_VTRNG_VRAND0_2 0x186 -+#define NIST_TRNG_EDU_VTRNG_VRAND0_3 0x187 -+#define NIST_TRNG_EDU_VTRNG_VCTRL1 0x188 -+#define NIST_TRNG_EDU_VTRNG_VSTAT1 0x189 -+#define NIST_TRNG_EDU_VTRNG_VIE1 0x18A -+#define NIST_TRNG_EDU_VTRNG_VISTAT1 0x18B -+#define NIST_TRNG_EDU_VTRNG_VRAND1_0 0x18C -+#define NIST_TRNG_EDU_VTRNG_VRAND1_1 0x18D -+#define NIST_TRNG_EDU_VTRNG_VRAND1_2 0x18E -+#define NIST_TRNG_EDU_VTRNG_VRAND1_3 0x18F -+#define NIST_TRNG_EDU_VTRNG_VCTRL2 0x190 -+#define NIST_TRNG_EDU_VTRNG_VSTAT2 0x191 -+#define NIST_TRNG_EDU_VTRNG_VIE2 0x192 -+#define NIST_TRNG_EDU_VTRNG_VISTAT2 0x193 -+#define NIST_TRNG_EDU_VTRNG_VRAND2_0 0x194 -+#define NIST_TRNG_EDU_VTRNG_VRAND2_1 0x195 -+#define NIST_TRNG_EDU_VTRNG_VRAND2_2 0x196 -+#define NIST_TRNG_EDU_VTRNG_VRAND2_3 0x197 -+#define NIST_TRNG_EDU_VTRNG_VCTRL3 0x198 -+#define NIST_TRNG_EDU_VTRNG_VSTAT3 0x199 -+#define NIST_TRNG_EDU_VTRNG_VIE3 0x19A -+#define NIST_TRNG_EDU_VTRNG_VISTAT3 0x19B -+#define NIST_TRNG_EDU_VTRNG_VRAND3_0 0x19C -+#define NIST_TRNG_EDU_VTRNG_VRAND3_1 0x19D -+#define NIST_TRNG_EDU_VTRNG_VRAND3_2 0x19E -+#define NIST_TRNG_EDU_VTRNG_VRAND3_3 0x19F -+#define NIST_TRNG_EDU_VTRNG_VCTRL4 0x1A0 -+#define NIST_TRNG_EDU_VTRNG_VSTAT4 0x1A1 -+#define NIST_TRNG_EDU_VTRNG_VIE4 0x1A2 -+#define NIST_TRNG_EDU_VTRNG_VISTAT4 0x1A3 -+#define NIST_TRNG_EDU_VTRNG_VRAND4_0 0x1A4 -+#define NIST_TRNG_EDU_VTRNG_VRAND4_1 0x1A5 -+#define NIST_TRNG_EDU_VTRNG_VRAND4_2 0x1A6 -+#define NIST_TRNG_EDU_VTRNG_VRAND4_3 0x1A7 -+#define NIST_TRNG_EDU_VTRNG_VCTRL5 0x1A8 -+#define NIST_TRNG_EDU_VTRNG_VSTAT5 0x1A9 -+#define NIST_TRNG_EDU_VTRNG_VIE5 0x1AA -+#define NIST_TRNG_EDU_VTRNG_VISTAT5 0x1AB -+#define NIST_TRNG_EDU_VTRNG_VRAND5_0 0x1AC -+#define NIST_TRNG_EDU_VTRNG_VRAND5_1 0x1AD -+#define NIST_TRNG_EDU_VTRNG_VRAND5_2 0x1AE -+#define NIST_TRNG_EDU_VTRNG_VRAND5_3 0x1AF -+#define NIST_TRNG_EDU_VTRNG_VCTRL6 0x1B0 -+#define NIST_TRNG_EDU_VTRNG_VSTAT6 0x1B1 -+#define NIST_TRNG_EDU_VTRNG_VIE6 0x1B2 -+#define NIST_TRNG_EDU_VTRNG_VISTAT6 0x1B3 -+#define NIST_TRNG_EDU_VTRNG_VRAND6_0 0x1B4 -+#define NIST_TRNG_EDU_VTRNG_VRAND6_1 0x1B5 -+#define NIST_TRNG_EDU_VTRNG_VRAND6_2 0x1B6 -+#define NIST_TRNG_EDU_VTRNG_VRAND6_3 0x1B7 -+#define NIST_TRNG_EDU_VTRNG_VCTRL7 0x1B8 -+#define NIST_TRNG_EDU_VTRNG_VSTAT7 0x1B9 -+#define NIST_TRNG_EDU_VTRNG_VIE7 0x1BA -+#define NIST_TRNG_EDU_VTRNG_VISTAT7 0x1BB -+#define NIST_TRNG_EDU_VTRNG_VRAND7_0 0x1BC -+#define NIST_TRNG_EDU_VTRNG_VRAND7_1 0x1BD -+#define NIST_TRNG_EDU_VTRNG_VRAND7_2 0x1BE -+#define NIST_TRNG_EDU_VTRNG_VRAND7_3 0x1BF -+ -+#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_NOP 0x0 -+#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_GET_RANDOM 0x1 -+#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_INIT 0x2 -+ -+#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_MASK 0x3Ul -+#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_SET(y, x) (((y) & ~(NIST_TRNG_EDU_VTRNG_VCTRL_CMD_MASK)) | ((x))) -+ -+/* CTRL */ -+#define NIST_TRNG_REG_CTRL_CMD_NOP 0 -+#define NIST_TRNG_REG_CTRL_CMD_GEN_NOISE 1 -+#define NIST_TRNG_REG_CTRL_CMD_GEN_NONCE 2 -+#define NIST_TRNG_REG_CTRL_CMD_CREATE_STATE 3 -+#define NIST_TRNG_REG_CTRL_CMD_RENEW_STATE 4 -+#define NIST_TRNG_REG_CTRL_CMD_REFRESH_ADDIN 5 -+#define NIST_TRNG_REG_CTRL_CMD_GEN_RANDOM 6 -+#define NIST_TRNG_REG_CTRL_CMD_ADVANCE_STATE 7 -+#define NIST_TRNG_REG_CTRL_CMD_KAT 8 -+#define NIST_TRNG_REG_CTRL_CMD_ZEROIZE 15 -+ -+/* EDU CTRL */ -+#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_DISABLE_TO_HOLD 0 -+#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE 1 -+#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_DISABLE_TO_IDLE 2 -+#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE 3 -+ -+#define NIST_TRNG_EDU_RNC_CTRL_CMD_MASK 0x3Ul -+#define NIST_TRNG_EDU_RNC_CTRL_CMD_SET(y, x) (((y) & ~(NIST_TRNG_EDU_RNC_CTRL_CMD_MASK)) | ((x))) -+ -+/* EDU_FLUSH_CTRL */ -+#define _NIST_TRNG_EDU_FLUSH_CTRL_CH2_RBC 3 -+#define _NIST_TRNG_EDU_FLUSH_CTRL_CH1_RBC 2 -+#define _NIST_TRNG_EDU_FLUSH_CTRL_CH0_RBC 1 -+#define _NIST_TRNG_EDU_FLUSH_CTRL_FIFO 0 -+ -+#define NIST_TRNG_EDU_FLUSH_CTRL_CH2_RBC BIT(_NIST_TRNG_EDU_FLUSH_CTRL_CH2_RBC) -+#define NIST_TRNG_EDU_FLUSH_CTRL_CH1_RBC BIT(_NIST_TRNG_EDU_FLUSH_CTRL_CH1_RBC) -+#define NIST_TRNG_EDU_FLUSH_CTRL_CH0_RBC BIT(_NIST_TRNG_EDU_FLUSH_CTRL_CH0_RBC) -+#define NIST_TRNG_EDU_FLUSH_CTRL_FIFO BIT(_NIST_TRNG_EDU_FLUSH_CTRL_FIFO) -+ -+/*EDU_RBC_CTRL*/ -+#define _NIST_TRNG_EDU_RBC_CTRL_CH2_URUN_BLANK 28 -+#define _NIST_TRNG_EDU_RBC_CTRL_CH1_URUN_BLANK 26 -+#define _NIST_TRNG_EDU_RBC_CTRL_CH0_URUN_BLANK 24 -+#define _NIST_TRNG_EDU_RBC_CTRL_CH2_RATE 16 -+#define _NIST_TRNG_EDU_RBC_CTRL_CH1_RATE 8 -+#define _NIST_TRNG_EDU_RBC_CTRL_CH0_RATE 0 -+ -+#define _NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK 0xFUL -+#define _NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK 0x3UL -+ -+#define NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(z, y, x) (((y) & ~(_NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK << (x))) | ((z) << (x))) -+#define NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(z, y, x) (((y) & ~(_NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK << (x))) | ((z) << (x))) -+ -+#define NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(y, x) ((_NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK) & ((y) >> (x))) -+#define NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(y, x) ((_NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK) & ((y) >> (x))) -+ -+#define NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE_AFTER_RESET 0x0 -+#define NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK_AFTER_RESET 0x3 -+ -+/* MODE */ -+#define _NIST_TRNG_REG_MODE_KAT_SEL 7 -+#define _NIST_TRNG_REG_MODE_KAT_VEC 5 -+#define _NIST_TRNG_REG_MODE_ADDIN_PRESENT 4 -+#define _NIST_TRNG_REG_MODE_PRED_RESIST 3 -+#define _NIST_TRNG_REG_MODE_SEC_ALG 0 -+ -+#define NIST_TRNG_REG_MODE_ADDIN_PRESENT BIT(_NIST_TRNG_REG_MODE_ADDIN_PRESENT) -+#define NIST_TRNG_REG_MODE_PRED_RESIST BIT(_NIST_TRNG_REG_MODE_PRED_RESIST) -+#define NIST_TRNG_REG_MODE_SEC_ALG BIT(_NIST_TRNG_REG_MODE_SEC_ALG) -+ -+/* SMODE */ -+#define _NIST_TRNG_REG_SMODE_NOISE_COLLECT 31 -+#define _NIST_TRNG_REG_SMODE_INDIV_HT_DISABLE 16 -+#define _NIST_TRNG_REG_SMODE_MAX_REJECTS 2 -+#define _NIST_TRNG_REG_SMODE_MISSION_MODE 1 -+#define _NIST_TRNG_REG_SMODE_SECURE_EN _NIST_TRNG_REG_SMODE_MISSION_MODE -+#define _NIST_TRNG_REG_SMODE_NONCE 0 -+ -+#define NIST_TRNG_REG_SMODE_MAX_REJECTS(x) ((x) << _NIST_TRNG_REG_SMODE_MAX_REJECTS) -+#define NIST_TRNG_REG_SMODE_SECURE_EN(x) ((x) << _NIST_TRNG_REG_SMODE_SECURE_EN) -+#define NIST_TRNG_REG_SMODE_NONCE BIT(_NIST_TRNG_REG_SMODE_NONCE) -+ -+/* STAT */ -+#define _NIST_TRNG_REG_STAT_BUSY 31 -+#define _NIST_TRNG_REG_STAT_STARTUP_TEST_IN_PROG 10 -+#define _NIST_TRNG_REG_STAT_STARTUP_TEST_STUCK 9 -+#define _NIST_TRNG_REG_STAT_DRBG_STATE 7 -+#define _NIST_TRNG_REG_STAT_SECURE 6 -+#define _NIST_TRNG_REG_STAT_NONCE_MODE 5 -+#define _NIST_TRNG_REG_STAT_SEC_ALG 4 -+#define _NIST_TRNG_REG_STAT_LAST_CMD 0 -+ -+#define NIST_TRNG_REG_STAT_BUSY BIT(_NIST_TRNG_REG_STAT_BUSY) -+//#define NIST_TRNG_REG_STAT_DRBG_STATE (1UL<<_NIST_TRNG_REG_STAT_DRBG_STATE) -+//#define NIST_TRNG_REG_STAT_SECURE (1UL << _NIST_TRNG_REG_STAT_SECURE) -+//#define NIST_TRNG_REG_STAT_NONCE_MODE (1UL << _NIST_TRNG_REG_STAT_NONCE_MODE) -+//#define NIST_TRNG_REG_STAT_SEC_ALG (1UL << _NIST_TRNG_REG_STAT_SEC_ALG) -+//#define NIST_TRNG_REG_STAT_LAST_CMD(x) (((x) >> _NIST_TRNG_REG_STAT_LAST_CMD)&0xF) -+ -+/*EDU_STAT*/ -+ -+#define NIST_TRNG_EDU_STAT_FIFO_LEVEL(x) (((x) >> 24) & 255) -+#define NIST_TRNG_EDU_STAT_TTT_INDEX(x) (((x) >> 16) & 255) -+#define NIST_TRNG_EDU_STAT_RNC_BUSY(x) (((x) >> 3) & 7) -+#define NIST_TRNG_EDU_STAT_RNC_ENABLED(x) (((x) >> 2) & 1) -+#define NIST_TRNG_EDU_STAT_FIFO_EMPTY(x) (((x) >> 1) & 1) -+#define NIST_TRNG_EDU_STAT_FIFO_FULL(x) ((x) & 1) -+ -+/* IE */ -+#define _NIST_TRNG_REG_IE_GLBL 31 -+#define _NIST_TRNG_REG_IE_DONE 4 -+#define _NIST_TRNG_REG_IE_ALARMS 3 -+#define _NIST_TRNG_REG_IE_NOISE_RDY 2 -+#define _NIST_TRNG_REG_IE_KAT_COMPLETE 1 -+#define _NIST_TRNG_REG_IE_ZEROIZE 0 -+ -+#define NIST_TRNG_REG_IE_GLBL BIT(_NIST_TRNG_REG_IE_GLBL) -+#define NIST_TRNG_REG_IE_DONE BIT(_NIST_TRNG_REG_IE_DONE) -+#define NIST_TRNG_REG_IE_ALARMS BIT(_NIST_TRNG_REG_IE_ALARMS) -+#define NIST_TRNG_REG_IE_NOISE_RDY BIT(_NIST_TRNG_REG_IE_NOISE_RDY) -+#define NIST_TRNG_REG_IE_KAT_COMPLETE BIT(_NIST_TRNG_REG_IE_KAT_COMPLETE) -+#define NIST_TRNG_REG_IE_ZEROIZE BIT(_NIST_TRNG_REG_IE_ZEROIZE) -+ -+/* ISTAT */ -+#define _NIST_TRNG_REG_ISTAT_DONE 4 -+#define _NIST_TRNG_REG_ISTAT_ALARMS 3 -+#define _NIST_TRNG_REG_ISTAT_NOISE_RDY 2 -+#define _NIST_TRNG_REG_ISTAT_KAT_COMPLETE 1 -+#define _NIST_TRNG_REG_ISTAT_ZEROIZE 0 -+ -+#define NIST_TRNG_REG_ISTAT_DONE BIT(_NIST_TRNG_REG_ISTAT_DONE) -+#define NIST_TRNG_REG_ISTAT_ALARMS BIT(_NIST_TRNG_REG_ISTAT_ALARMS) -+#define NIST_TRNG_REG_ISTAT_NOISE_RDY BIT(_NIST_TRNG_REG_ISTAT_NOISE_RDY) -+#define NIST_TRNG_REG_ISTAT_KAT_COMPLETE BIT(_NIST_TRNG_REG_ISTAT_KAT_COMPLETE) -+#define NIST_TRNG_REG_ISTAT_ZEROIZE BIT(_NIST_TRNG_REG_ISTAT_ZEROIZE) -+ -+/*EDU_ISTAT*/ -+ -+#define _NIST_TRNG_EDU_ISTAT_CH2_RBC_URUN 8 -+#define _NIST_TRNG_EDU_ISTAT_CH1_RBC_URUN 7 -+#define _NIST_TRNG_EDU_ISTAT_CH0_RBC_URUN 6 -+#define _NIST_TRNG_EDU_ISTAT_PRIVATE_VTRNG 5 -+#define _NIST_TRNG_EDU_ISTAT_WAIT_EXP_TIMEOUT 4 -+#define _NIST_TRNG_EDU_ISTAT_RNC_DRVN_OFFLINE 3 -+#define _NIST_TRNG_EDU_ISTAT_FIFO_URUN 2 -+#define _NIST_TRNG_EDU_ISTAT_ACCESS_VIOL 1 -+#define _NIST_TRNG_EDU_ISTAT_RESEED_REMINDER 0 -+ -+#define NIST_TRNG_EDU_ISTAT_CH2_RBC_URUN BIT(_NIST_TRNG_EDU_ISTAT_CH2_RBC_URUN) -+#define NIST_TRNG_EDU_ISTAT_CH1_RBC_URUN BIT(_NIST_TRNG_EDU_ISTAT_CH1_RBC_URUN) -+#define NIST_TRNG_EDU_ISTAT_CH0_RBC_URUN BIT(_NIST_TRNG_EDU_ISTAT_CH0_RBC_URUN) -+#define NIST_TRNG_EDU_ISTAT_PRIVATE_VTRNG BIT(_NIST_TRNG_EDU_ISTAT_PRIVATE_VTRNG) -+#define NIST_TRNG_EDU_ISTAT_WAIT_EXP_TIMEOUT BIT(_NIST_TRNG_EDU_ISTAT_WAIT_EXP_TIMEOUT) -+#define NIST_TRNG_EDU_ISTAT_RNC_DRVN_OFFLINE BIT(_NIST_TRNG_EDU_ISTAT_RNC_DRVN_OFFLINE) -+#define NIST_TRNG_EDU_ISTAT_FIFO_URUN BIT(_NIST_TRNG_EDU_ISTAT_FIFO_URUN) -+#define NIST_TRNG_EDU_ISTAT_ACCESS_VIOL BIT(_NIST_TRNG_EDU_ISTAT_ACCESS_VIOL) -+#define NIST_TRNG_EDU_ISTAT_RESEED_REMINDER BIT(_NIST_TRNG_EDU_ISTAT_RESEED_REMINDER) -+ -+/* ALARMS */ -+#define NIST_TRNG_REG_ALARM_ILLEGAL_CMD_SEQ BIT(4) -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_OK 0 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_KAT_STAT 1 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_KAT 2 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_MONOBIT 3 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_RUN 4 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_LONGRUN 5 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_AUTOCORRELATION 6 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_POKER 7 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_REPETITION_COUNT 8 -+#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_ADAPATIVE_PROPORTION 9 -+ -+/* COREKIT_REL */ -+#define NIST_TRNG_REG_EXT_ENUM(x) (((x) >> 28) & 0xF) -+#define NIST_TRNG_REG_EXT_VER(x) (((x) >> 23) & 0xFF) -+#define NIST_TRNG_REG_REL_NUM(x) ((x) & 0xFFFF) -+ -+// This will be deleted ?? per comments in hw details. ie use CFG -+/* FEATURES */ -+#define NIST_TRNG_REG_FEATURES_AES_256(x) (((x) >> 9) & 1) -+#define NIST_TRNG_REG_FEATURES_EXTRA_PS_PRESENT(x) (((x) >> 8) & 1) -+#define NIST_TRNG_REG_FEATURES_DIAG_LEVEL_NS(x) (((x) >> 7) & 1) -+#define NIST_TRNG_REG_FEATURES_DIAG_LEVEL_BASIC_TRNG(x) (((x) >> 4) & 7) -+#define NIST_TRNG_REG_FEATURES_DIAG_LEVEL_ST_HLT(x) (((x) >> 1) & 7) -+#define NIST_TRNG_REG_FEATURES_SECURE_RST_STATE(x) ((x) & 1) -+ -+/* build_CFG0 */ -+#define NIST_TRNG_REG_CFG0_PERSONILIZATION_STR(x) (((x) >> 14) & 1) -+#define NIST_TRNG_REG_CFG0_AES_MAX_KEY_SIZE(x) (((x) >> 13) & 1) -+#define NIST_TRNG_REG_CFG0_AES_DATAPATH(x) (((x) >> 12) & 1) -+#define NIST_TRNG_REG_CFG0_EDU_PRESENT(x) (((x) >> 11) & 1) -+#define NIST_TRNG_REG_CFG0_BACGROUND_NOISE(x) (((x) >> 10) & 1) -+#define NIST_TRNG_REG_CFG0_CDC_SYNCH_DEPTH(x) (((x) >> 8) & 3) -+#define NIST_TRNG_REG_CFG0_BG8(x) (((x) >> 7) & 1) -+#define NIST_TRNG_REG_CFG0_CORE_TYPE(x) ((x) & 3) -+ -+/* build_CFG1 */ -+#define NIST_TRNG_REG_CFG1_ENT_SRC_REP_MIN_ENTROPY(x) (((x) >> 24) & 255) -+#define NIST_TRNG_REG_CFG1_ENT_SRC_REP_TEST(x) (((x) >> 23) & 1) -+#define NIST_TRNG_REG_CFG1_ENT_SRC_REP_SMPL_SIZE(x) (((x) >> 20) & 7) -+#define NIST_TRNG_REG_CFG1_RAW_HT_REP_TEST(x) (((x) >> 19) & 1) -+#define NIST_TRNG_REG_CFG1_RAW_HT_ADAP_TEST(x) (((x) >> 16) & 7) -+#define NIST_TRNG_REG_CFG1_POKER_TEST(x) (((x) >> 15) & 1) -+#define NIST_TRNG_REG_CFG1_RUN_TEST(x) (((x) >> 14) & 1) -+#define NIST_TRNG_REG_CFG1_MONO_BIT_TEST(x) (((x) >> 13) & 1) -+#define NIST_TRNG_REG_CFG1_AUTO_CORRELATION_TEST(x) (((x) >> 12) & 1) -+#define NIST_TRNG_REG_CFG1_STICKY_STARTUP(x) (((x) >> 8) & 1) -+#define NIST_TRNG_REG_CFG1_NUM_RAW_NOISE_BLKS(x) ((x) & 255) -+ -+/* EDU_BUILD_CFG0 */ -+#define NIST_TRNG_REG_EDU_CFG0_RBC2_RATE_WIDTH(x) (((x) >> 20) & 7) -+#define NIST_TRNG_REG_EDU_CFG0_RBC1_RATE_WIDTH(x) (((x) >> 16) & 7) -+#define NIST_TRNG_REG_EDU_CFG0_RBC0_RATE_WIDTH(x) (((x) >> 12) & 7) -+#define NIST_TRNG_REG_EDU_CFG0_PUBLIC_VTRNG_CHANNELS(x) (((x) >> 8) & 15) -+#define NIST_TRNG_REG_EDU_CFG0_ESM_CHANNEL(x) (((x) >> 6) & 1) -+#define NIST_TRNG_REG_EDU_CFG0_RBC_CHANNELS(x) (((x) >> 4) & 3) -+#define NIST_TRNG_REG_EDU_CFG0_FIFO_DEPTH(x) (((x) >> 2) & 7) -+ -+/* EDU_VSTAT */ -+#define NIST_TRNG_REG_EDU_VSTAT_BUSY(x) (((x) >> 31) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_RNC_ENABLED(x) (((x) >> 30) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SEED_ENUM(x) (((x) >> 28) & 3) -+#define NIST_TRNG_REG_EDU_VSTAT_RWUE(x) (((x) >> 27) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_RWNE(x) (((x) >> 26) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SRWE(x) (((x) >> 25) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_ANY_RW1(x) (((x) >> 24) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_BCKGRND_NOISE(x) (((x) >> 23) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_RNC_FIFO_EMPTY(x) (((x) >> 22) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI3(x) (((x) >> 15) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI2(x) (((x) >> 14) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI1(x) (((x) >> 13) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI0(x) (((x) >> 12) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD3(x) (((x) >> 11) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD2(x) (((x) >> 10) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD1(x) (((x) >> 9) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD0(x) (((x) >> 8) & 1) -+#define NIST_TRNG_REG_EDU_VSTAT_CURRENT_CMD(x) (((x) >> 4) & 15) -+#define NIST_TRNG_REG_EDU_VSTAT_LAST_CMD(x) ((x) & 15) -+ -+#define _NIST_TRNG_REG_SMODE_MAX_REJECTS_MASK 255UL -+#define _NIST_TRNG_REG_SMODE_SECURE_EN_MASK 1UL -+#define _NIST_TRNG_REG_SMODE_NONCE_MASK 1UL -+#define _NIST_TRNG_REG_MODE_SEC_ALG_MASK 1UL -+#define _NIST_TRNG_REG_MODE_ADDIN_PRESENT_MASK 1UL -+#define _NIST_TRNG_REG_MODE_PRED_RESIST_MASK 1UL -+#define _NIST_TRNG_REG_MODE_KAT_SEL_MASK 3UL -+#define _NIST_TRNG_REG_MODE_KAT_VEC_MASK 3UL -+#define _NIST_TRNG_REG_STAT_DRBG_STATE_MASK 3UL -+#define _NIST_TRNG_REG_STAT_SECURE_MASK 1UL -+#define _NIST_TRNG_REG_STAT_NONCE_MASK 1UL -+ -+#define NIST_TRNG_REG_SMODE_SET_MAX_REJECTS(y, x) (((y) & ~(_NIST_TRNG_REG_SMODE_MAX_REJECTS_MASK << _NIST_TRNG_REG_SMODE_MAX_REJECTS)) | ((x) << _NIST_TRNG_REG_SMODE_MAX_REJECTS)) -+#define NIST_TRNG_REG_SMODE_SET_SECURE_EN(y, x) (((y) & ~(_NIST_TRNG_REG_SMODE_SECURE_EN_MASK << _NIST_TRNG_REG_SMODE_SECURE_EN)) | ((x) << _NIST_TRNG_REG_SMODE_SECURE_EN)) -+#define NIST_TRNG_REG_SMODE_SET_NONCE(y, x) (((y) & ~(_NIST_TRNG_REG_SMODE_NONCE_MASK << _NIST_TRNG_REG_SMODE_NONCE)) | ((x) << _NIST_TRNG_REG_SMODE_NONCE)) -+#define NIST_TRNG_REG_SMODE_GET_MAX_REJECTS(x) (((x) >> _NIST_TRNG_REG_SMODE_MAX_REJECTS) & _NIST_TRNG_REG_SMODE_MAX_REJECTS_MASK) -+#define NIST_TRNG_REG_SMODE_GET_SECURE_EN(x) (((x) >> _NIST_TRNG_REG_SMODE_SECURE_EN) & _NIST_TRNG_REG_SMODE_SECURE_EN_MASK) -+#define NIST_TRNG_REG_SMODE_GET_NONCE(x) (((x) >> _NIST_TRNG_REG_SMODE_NONCE) & _NIST_TRNG_REG_SMODE_NONCE_MASK) -+ -+#define NIST_TRNG_REG_MODE_SET_SEC_ALG(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_SEC_ALG_MASK << _NIST_TRNG_REG_MODE_SEC_ALG)) | ((x) << _NIST_TRNG_REG_MODE_SEC_ALG)) -+#define NIST_TRNG_REG_MODE_SET_PRED_RESIST(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_PRED_RESIST_MASK << _NIST_TRNG_REG_MODE_PRED_RESIST)) | ((x) << _NIST_TRNG_REG_MODE_PRED_RESIST)) -+#define NIST_TRNG_REG_MODE_SET_ADDIN_PRESENT(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_ADDIN_PRESENT_MASK << _NIST_TRNG_REG_MODE_ADDIN_PRESENT)) | ((x) << _NIST_TRNG_REG_MODE_ADDIN_PRESENT)) -+#define NIST_TRNG_REG_MODE_SET_KAT_SEL(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_KAT_SEL_MASK << _NIST_TRNG_REG_MODE_KAT_SEL)) | ((x) << _NIST_TRNG_REG_MODE_KAT_SEL)) -+#define NIST_TRNG_REG_MODE_SET_KAT_VEC(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_KAT_VEC_MASK << _NIST_TRNG_REG_MODE_KAT_VEC)) | ((x) << _NIST_TRNG_REG_MODE_KAT_VEC)) -+#define NIST_TRNG_REG_MODE_GET_SEC_ALG(x) (((x) >> _NIST_TRNG_REG_MODE_SEC_ALG) & _NIST_TRNG_REG_MODE_SEC_ALG_MASK) -+#define NIST_TRNG_REG_MODE_GET_PRED_RESIST(x) (((x) >> _NIST_TRNG_REG_MODE_PRED_RESIST) & _NIST_TRNG_REG_MODE_PRED_RESIST_MASK) -+#define NIST_TRNG_REG_MODE_GET_ADDIN_PRESENT(x) (((x) >> _NIST_TRNG_REG_MODE_ADDIN_PRESENT) & _NIST_TRNG_REG_MODE_ADDIN_PRESENT_MASK) -+#define NIST_TRNG_REG_STAT_GET_DRBG_STATE(x) (((x) >> _NIST_TRNG_REG_STAT_DRBG_STATE) & _NIST_TRNG_REG_STAT_DRBG_STATE_MASK) -+#define NIST_TRNG_REG_STAT_GET_SECURE(x) (((x) >> _NIST_TRNG_REG_STAT_SECURE) & _NIST_TRNG_REG_STAT_SECURE_MASK) -+#define NIST_TRNG_REG_STAT_GET_NONCE(x) (((x) >> _NIST_TRNG_REG_STAT_NONCE_MODE) & _NIST_TRNG_REG_STAT_NONCE_MASK) ++<pi1_i3c8 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06018000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+#endif -diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h ---- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++<pi1_i3c9 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+#ifndef NISTTRNG_PRIVATE_H -+#define NISTTRNG_PRIVATE_H -+ -+#include "elppdu.h" -+#include "nisttrng_hw.h" -+#include "nisttrng_common.h" -+ -+int nisttrng_wait_on_busy(struct nist_trng_state *state); -+int nisttrng_wait_on_done(struct nist_trng_state *state); -+int nisttrng_wait_on_noise_rdy(struct nist_trng_state *state); -+int nisttrng_get_alarms(struct nist_trng_state *state); -+int nisttrng_reset_state(struct nist_trng_state *state); -+ -+/* ---------- Reminders ---------- */ -+int nisttrng_reset_counters(struct nist_trng_state *state); -+int nisttrng_set_reminder_max_bits_per_req(struct nist_trng_state *state, unsigned long max_bits_per_req); -+int nisttrng_set_reminder_max_req_per_seed(struct nist_trng_state *state, unsigned long long max_req_per_seed); -+int nisttrng_check_seed_lifetime(struct nist_trng_state *state); -+ -+/* ---------- Set field APIs ---------- */ -+int nisttrng_set_sec_strength(struct nist_trng_state *state, int req_sec_strength); -+int nisttrng_set_addin_present(struct nist_trng_state *state, int addin_present); -+int nisttrng_set_pred_resist(struct nist_trng_state *state, int pred_resist); -+int nisttrng_set_secure_mode(struct nist_trng_state *state, int secure_mode); -+int nisttrng_set_nonce_mode(struct nist_trng_state *state, int nonce_mode); -+ -+/* ---------- Load data APIs ---------- */ -+int nisttrng_load_ps_addin(struct nist_trng_state *state, void *input_str); -+ -+/* ---------- Command APIs ---------- */ -+int nisttrng_get_entropy_input(struct nist_trng_state *state, void *input_nonce, int nonce_operation); -+int nisttrng_refresh_addin(struct nist_trng_state *state, void *addin_str); -+int nisttrng_gen_random(struct nist_trng_state *state, void *random_bits, unsigned long req_num_bytes); -+int nisttrng_advance_state(struct nist_trng_state *state); -+int nisttrng_kat(struct nist_trng_state *state, int kat_sel, int kat_vec); -+int nisttrng_full_kat(struct nist_trng_state *state); -+int nisttrng_zeroize(struct nist_trng_state *state); -+ -+/* ---------- edu related ---------- */ -+ -+int nisttrng_rnc(struct nist_trng_state *state, int rnc_ctrl_cmd); -+int nisttrng_wait_fifo_full(struct nist_trng_state *state); -+#endif -diff --git a/drivers/char/hw_random/dwc/src/trng/include/synversion.h b/drivers/char/hw_random/dwc/src/trng/include/synversion.h ---- a/drivers/char/hw_random/dwc/src/trng/include/synversion.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/include/synversion.h 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++<pi1_i3c10 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601A000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+#ifndef VERSION_H -+#define VERSION_H ++<pi1_i3c11 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+#define TRNG_VERSION "1.00a" ++<pi1_i3c12 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601C000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+#endif -diff --git a/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c b/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c ---- a/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c 2025-12-23 10:16:19.524059486 +0000 -@@ -0,0 +1,2170 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2017 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++<pi1_i3c13 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++<pi1_i3c14 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601E000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+#include -+#include ++<pi1_i3c15 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+#include "nisttrng.h" ++&i2c6 { ++ status = "disabled"; ++}; + -+#define SYNOPSYS_HWRNG_DRIVER_NAME "hwrng-nist_trng" ++&i2c7 { ++ status = "disabled"; ++}; + -+#define num_gen_bytes 64 -+static unsigned long max_reads = 128; ++// The following I2C buses require enabling according to the ast2700-dcscm.dts. ++// i2c8 / i2c9 / i2c10 + -+struct synopsys_nisttrng_driver { -+ struct nist_trng_state nisttrng; -+ void *hwrng_drv; -+ void *crypto_drv; -+ unsigned char rand_out[num_gen_bytes]; ++&i2c11 { ++ status = "disabled"; +}; + -+static unsigned int xxd_vtrng; ++<pi1_i2c0 { ++ status = "okay"; ++}; + -+static void nisttrng_reinit(struct nist_trng_state *nist_trng) -+{ -+ int err; ++<pi1_i2c1 { ++ status = "okay"; ++}; + -+ err = nisttrng_uninstantiate(nist_trng); -+ if (err && err != CRYPTO_NOT_INSTANTIATED) -+ goto ERR; ++<pi1_i2c2 { ++ status = "okay"; ++}; + -+ err = nisttrng_instantiate(nist_trng, 128, 1, NULL); -+ if (err) -+ goto ERR; ++<pi1_i2c3 { ++ status = "okay"; ++}; + -+ERR: -+ DEBUG("NIST_TRNG: Trying to reinitialize after a fatal alarm: %d\n", -+ err); -+} ++<pi1_i2c4 { ++ status = "okay"; ++}; + -+static int nisttrng_platform_driver_read(struct platform_device *pdev, -+ void *buf, size_t max, bool wait) -+{ -+ struct synopsys_nisttrng_driver *data = 0; -+ int nisttrng_error = -1; -+ u32 *out = kmalloc(max, GFP_KERNEL); -+ unsigned int vtrng; ++<pi1_i2c5 { ++ status = "okay"; ++}; + -+ if (!out) { -+ SYNHW_PRINT("memory not allocated\n"); -+ return -1; -+ } ++<pi1_i2c6 { ++ status = "okay"; ++}; + -+ if (!pdev || !buf || !max) -+ return nisttrng_error; ++<pi1_i2c7 { ++ status = "okay"; ++}; + -+ data = platform_get_drvdata(pdev); -+ if (data == 0) -+ return nisttrng_error; ++<pi1_i2c8 { ++ status = "okay"; ++}; + -+ if (data->nisttrng.config.build_cfg0.edu_present) { -+ vtrng = xxd_vtrng % ((data->nisttrng.config.edu_build_cfg0 -+ .public_vtrng_channels) + -+ 1); -+ if (vtrng == 0) { -+ /* private vtrng */ -+ nisttrng_error = nisttrng_generate(&data->nisttrng, out, max, -+ data->nisttrng.status.sec_strength ? 256 : 128, -+ data->nisttrng.status.pred_resist, NULL); -+ } else { -+ /* public vtrng */ -+ nisttrng_error = nisttrng_generate_public_vtrng(&data->nisttrng, out, max, vtrng - 1); -+ } -+ xxd_vtrng++; -+ } else { -+ /* nist core vtrng */ -+ nisttrng_error = nisttrng_generate(&data->nisttrng, out, max, -+ data->nisttrng.status.sec_strength ? 256 : 128, -+ data->nisttrng.status.pred_resist, NULL); -+ } -+ if (nisttrng_error < 0) { -+ if (data->nisttrng.status.alarm_code) -+ nisttrng_reinit(&data->nisttrng); ++<pi1_i2c9 { ++ status = "okay"; ++}; + -+ return nisttrng_error; -+ } ++<pi1_i2c10 { ++ status = "okay"; ++}; + -+ memcpy(buf, out, max); -+ kfree(out); ++<pi1_i2c11 { ++ status = "okay"; ++}; + -+ return max; -+} ++<pi1_i2c12 { ++ status = "okay"; ++}; + -+static int nisttrng_hwrng_driver_read(struct hwrng *rng, void *buf, size_t max, -+ bool wait) -+{ -+ struct platform_device *pdev = 0; ++<pi1_i2c13 { ++ status = "okay"; ++}; + -+ if (rng == 0) -+ return -1; ++<pi1_i2c14 { ++ status = "okay"; ++}; + -+ pdev = (struct platform_device *)rng->priv; -+ return nisttrng_platform_driver_read(pdev, buf, max, wait); -+} ++<pi1_i2c15 { ++ status = "okay"; ++}; + -+static ssize_t ckr_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++&uart8 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,456 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ return sprintf(buf, "rel_num=%u, ext_ver=%u, ext_enum=%u\n", -+ priv->nisttrng.config.corekit_rel.rel_num, -+ priv->nisttrng.config.corekit_rel.ext_ver, -+ priv->nisttrng.config.corekit_rel.ext_enum); -+} ++/dts-v1/; + -+static ssize_t features_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++#include "ast2700a1-dcscm.dts" ++#include "aspeed-ltpi0.dtsi" + -+ return sprintf(buf, -+ "drbg_arch = %u, diag_basic_trng=%u, diag_st_hlt=%u, diag_ns=%u, secure_rst_state=%u, extra_ps_present=%u\n", -+ priv->nisttrng.config.features.drbg_arch, -+ priv->nisttrng.config.features.diag_level_basic_trng, -+ priv->nisttrng.config.features.diag_level_stat_hlt, -+ priv->nisttrng.config.features.diag_level_ns, -+ priv->nisttrng.config.features.secure_rst_state, -+ priv->nisttrng.config.features.extra_ps_present); -+} ++/ { ++ model = "AST2700A1-DCSCM_AST1700A1-EVB"; + -+static ssize_t secure_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan0: ltpi-pwm-fan0 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 0 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%s\n", NIST_TRNG_REG_SMODE_GET_SECURE_EN(pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_SMODE)) ? "on" : "off"); -+} ++ ltpi_fan1: ltpi-pwm-fan1 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 1 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t secure_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int ret; ++ ltpi_fan2: ltpi-pwm-fan2 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 2 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ ret = nisttrng_set_secure_mode(&priv->nisttrng, -+ sysfs_streq(buf, "on") ? 1 : 0); -+ if (ret) -+ return -1; ++ ltpi_fan3: ltpi-pwm-fan3 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 3 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return count; -+} ++ ltpi_fan4: ltpi-pwm-fan4 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 4 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t nonce_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan5: ltpi-pwm-fan5 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 5 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%s\n", NIST_TRNG_REG_SMODE_GET_NONCE(pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_SMODE)) ? "on" : "off"); -+} ++ ltpi_fan6: ltpi-pwm-fan6 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 6 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t nonce_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int ret; ++ ltpi_fan7: ltpi-pwm-fan7 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 7 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ ret = nisttrng_set_nonce_mode(&priv->nisttrng, -+ sysfs_streq(buf, "on") ? 1 : 0); -+ if (ret) -+ return -1; ++ ltpi_fan8: ltpi-pwm-fan8 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 8 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return count; -+} ++ ltpi_fan9: ltpi-pwm-fan9 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 9 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t sec_strength_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan10: ltpi-pwm-fan10 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 10 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%s\n", -+ priv->nisttrng.status.sec_strength ? "256" : "128"); -+} ++ ltpi_fan11: ltpi-pwm-fan11 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 11 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t sec_strength_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ int tmp; -+ int ret; ++ ltpi_fan12: ltpi-pwm-fan12 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 12 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ if (count > 8) -+ return -1; ++ ltpi_fan13: ltpi-pwm-fan13 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 13 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtoint(foo, 10, &tmp); -+ if (ret) -+ return ret; ++ ltpi_fan14: ltpi-pwm-fan14 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 14 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ ret = nisttrng_set_sec_strength(&priv->nisttrng, tmp); -+ if (ret) -+ return -1; ++ ltpi_fan15: ltpi-pwm-fan15 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 15 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return count; -+} ++ ltpi0-iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <<pi0_adc0 0>, <<pi0_adc0 1>, <<pi0_adc0 2>, <<pi0_adc0 3>, ++ <<pi0_adc0 4>, <<pi0_adc0 5>, <<pi0_adc0 6>, <<pi0_adc0 7>, ++ <<pi0_adc1 0>, <<pi0_adc1 1>, <<pi0_adc1 2>, <<pi0_adc1 3>, ++ <<pi0_adc1 4>, <<pi0_adc1 5>, <<pi0_adc1 6>, <<pi0_adc1 7>; ++ }; ++}; + -+static ssize_t rand_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ unsigned int x; -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_pwm_tach { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ltpi0_pwm0_default &pinctrl_ltpi0_pwm1_default ++ &pinctrl_ltpi0_pwm2_default &pinctrl_ltpi0_pwm3_default ++ &pinctrl_ltpi0_pwm4_default &pinctrl_ltpi0_pwm5_default ++ &pinctrl_ltpi0_pwm6_default &pinctrl_ltpi0_pwm7_default ++ &pinctrl_ltpi0_pwm8_default ++ &pinctrl_ltpi0_tach0_default &pinctrl_ltpi0_tach1_default ++ &pinctrl_ltpi0_tach2_default &pinctrl_ltpi0_tach3_default ++ &pinctrl_ltpi0_tach4_default &pinctrl_ltpi0_tach5_default ++ &pinctrl_ltpi0_tach6_default &pinctrl_ltpi0_tach7_default ++ &pinctrl_ltpi0_tach8_default &pinctrl_ltpi0_tach9_default ++ &pinctrl_ltpi0_tach10_default &pinctrl_ltpi0_tach11_default ++ &pinctrl_ltpi0_tach12_default &pinctrl_ltpi0_tach13_default ++ &pinctrl_ltpi0_tach14_default &pinctrl_ltpi0_tach15_default>; ++ ltpi_fan0 { ++ tach-ch = /bits/ 8 <0x0>; ++ }; ++ ltpi_fan1 { ++ tach-ch = /bits/ 8 <0x1>; ++ }; ++ ltpi_fan2 { ++ tach-ch = /bits/ 8 <0x2>; ++ }; ++ ltpi_fan3 { ++ tach-ch = /bits/ 8 <0x3>; ++ }; ++ ltpi_fan4 { ++ tach-ch = /bits/ 8 <0x4>; ++ }; ++ ltpi_fan5 { ++ tach-ch = /bits/ 8 <0x5>; ++ }; ++ ltpi_fan6 { ++ tach-ch = /bits/ 8 <0x6>; ++ }; ++ ltpi_fan7 { ++ tach-ch = /bits/ 8 <0x7>; ++ }; ++ ltpi_fan8 { ++ tach-ch = /bits/ 8 <0x8>; ++ }; ++ ltpi_fan9 { ++ tach-ch = /bits/ 8 <0x9>; ++ }; ++ ltpi_fan10 { ++ tach-ch = /bits/ 8 <0xA>; ++ }; ++ ltpi_fan11 { ++ tach-ch = /bits/ 8 <0xB>; ++ }; ++ ltpi_fan12 { ++ tach-ch = /bits/ 8 <0xC>; ++ }; ++ ltpi_fan13 { ++ tach-ch = /bits/ 8 <0xD>; ++ }; ++ ltpi_fan14 { ++ tach-ch = /bits/ 8 <0xE>; ++ }; ++ ltpi_fan15 { ++ tach-ch = /bits/ 8 <0xF>; ++ }; ++}; + -+ for (x = 0; x < 4; x++) { -+ sprintf(buf + 8 * x, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_RAND0 + 3 - x)); -+ } ++&sgpios { ++ /delete-property/ gpio-line-names; ++}; + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++<pi0_gpio { ++ /delete-property/ gpio-line-names; ++ /delete-node/ gpio_17; ++ /delete-node/ gpio_19; ++ /delete-node/ gpio_25; ++ /delete-node/ gpio_53; ++ /delete-node/ gpio_61; ++ /delete-node/ gpio_63; ++}; + -+static ssize_t seed_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ unsigned int x; -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_adc0 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ltpi0_adc0_default &pinctrl_ltpi0_adc1_default ++ &pinctrl_ltpi0_adc2_default &pinctrl_ltpi0_adc3_default ++ &pinctrl_ltpi0_adc4_default &pinctrl_ltpi0_adc5_default ++ &pinctrl_ltpi0_adc6_default &pinctrl_ltpi0_adc7_default>; ++}; + -+ for (x = 0; x < 12; x++) { -+ sprintf(buf + 8 * x, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_SEED0 + 11 - x)); -+ } -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++<pi0_adc1 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_ltpi0_adc8_default &pinctrl_ltpi0_adc9_default ++ &pinctrl_ltpi0_adc10_default &pinctrl_ltpi0_adc11_default ++ &pinctrl_ltpi0_adc12_default &pinctrl_ltpi0_adc13_default ++ &pinctrl_ltpi0_adc14_default &pinctrl_ltpi0_adc15_default>; ++}; + -+static ssize_t seed_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int x, tmp; -+ int ret; ++<pi0 { ++ i2c-tunneling = <0x0>; ++ status = "okay"; ++}; + -+ // string must be at least 12 32-bit words long in 0 padded hex -+ if (count < (2 * 12 * 4)) -+ return -1; ++<pi0_i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ for (x = 0; x < 12; x++) { -+ memcpy(foo, buf + x * 8, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i3c1 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SEED0 + x, -+ tmp); -+ } ++<pi0_i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ return count; -+} ++<pi0_i3c3 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+static ssize_t npa_data_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ unsigned int x; -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ for (x = 0; x < 16; x++) { -+ sprintf(buf + 8 * x, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_NPA_DATA0 + 15 - x)); -+ } ++<pi0_i3c5 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++<pi0_i3c6 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06016000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+static ssize_t npa_data_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int x, tmp; -+ int ret; ++<pi0_i3c7 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ // string must be at least 16 32-bit words long in 0 padded hex -+ if (count < (2 * 16 * 4)) -+ return -1; -+ -+ foo[8] = 0; -+ for (x = 0; x < 16; x++) { -+ memcpy(foo, buf + x * 8, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i3c8 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06018000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_NPA_DATA0 + x, tmp); -+ } ++<pi0_i3c9 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ return count; -+} ++<pi0_i3c10 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601A000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+static ssize_t ctrl_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i3c11 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_CTRL)); -+} ++<pi0_i3c12 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601C000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+static ssize_t ctrl_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++<pi0_i3c13 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++<pi0_i3c14 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601E000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i3c15 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_CTRL, tmp); -+ return count; -+} ++&i2c0 { ++ status = "disabled"; ++}; + -+static ssize_t istat_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++&i2c1 { ++ status = "disabled"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ISTAT)); -+} ++&i2c2 { ++ status = "disabled"; ++}; + -+static ssize_t istat_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++&i2c3 { ++ status = "disabled"; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++&i2c4 { ++ status = "disabled"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++&i2c5 { ++ status = "disabled"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ISTAT, tmp); -+ return count; -+} ++<pi0_i2c0 { ++ status = "okay"; ++}; + -+static ssize_t mode_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i2c1 { ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_MODE)); -+} ++<pi0_i2c2 { ++ status = "okay"; ++}; + -+static ssize_t mode_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++<pi0_i2c3 { ++ status = "okay"; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++<pi0_i2c4 { ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i2c5 { ++ status = "okay"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_MODE, tmp); ++<pi0_i2c6 { ++ status = "okay"; ++}; + -+ return count; -+} ++<pi0_i2c7 { ++ status = "okay"; ++}; + -+static ssize_t smode_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i2c8 { ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_SMODE)); -+} ++<pi0_i2c9 { ++ status = "okay"; ++}; + -+static ssize_t smode_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++<pi0_i2c10 { ++ status = "okay"; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++<pi0_i2c11 { ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i2c12 { ++ status = "okay"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, tmp); -+ return count; -+} ++<pi0_i2c13 { ++ status = "okay"; ++}; + -+static ssize_t alarm_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i2c14 { ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ALARM)); -+} ++<pi0_i2c15 { ++ status = "okay"; ++}; + -+static ssize_t alarm_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++&uart3 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,436 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++/dts-v1/; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++#include "ast2700a1-dcscm.dts" ++#include "aspeed-ltpi1800.dtsi" + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ALARM, tmp); -+ return count; -+} ++/ { ++ model = "AST2700A1-DCSCM_AST1800-EVB"; + -+static ssize_t stat_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan0: ltpi-pwm-fan0 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 0 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_STAT)); -+} ++ ltpi_fan1: ltpi-pwm-fan1 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 1 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t ia_wdata_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++ ltpi_fan2: ltpi-pwm-fan2 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 2 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++ ltpi_fan3: ltpi-pwm-fan3 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 3 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ ltpi_fan4: ltpi-pwm-fan4 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 4 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA, tmp); -+ return count; -+} ++ ltpi_fan5: ltpi-pwm-fan5 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 5 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t ia_wdata_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan6: ltpi-pwm-fan6 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 6 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA)); -+} ++ ltpi_fan7: ltpi-pwm-fan7 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 7 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t ia_rdata_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan8: ltpi-pwm-fan8 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 8 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_RDATA)); -+} ++ ltpi_fan9: ltpi-pwm-fan9 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 9 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t ia_addr_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++ ltpi_fan10: ltpi-pwm-fan10 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 10 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++ ltpi_fan11: ltpi-pwm-fan11 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 11 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ ltpi_fan12: ltpi-pwm-fan12 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 12 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, tmp); -+ return count; -+} ++ ltpi_fan13: ltpi-pwm-fan13 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 13 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t ia_addr_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ltpi_fan14: ltpi-pwm-fan14 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 14 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR)); -+} ++ ltpi_fan15: ltpi-pwm-fan15 { ++ compatible = "pwm-fan"; ++ pwms = <<pi0_pwm_tach 15 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+static ssize_t ia_cmd_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++ ltpi0-iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <<pi0_adc0 0>, <<pi0_adc0 1>, <<pi0_adc0 2>, <<pi0_adc0 3>, ++ <<pi0_adc0 4>, <<pi0_adc0 5>, <<pi0_adc0 6>, <<pi0_adc0 7>, ++ <<pi0_adc1 0>, <<pi0_adc1 1>, <<pi0_adc1 2>, <<pi0_adc1 3>, ++ <<pi0_adc1 4>, <<pi0_adc1 5>, <<pi0_adc1 6>, <<pi0_adc1 7>; ++ }; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++<pi0_jtag { ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_pwm_tach { ++ status = "okay"; ++ ltpi_fan0 { ++ tach-ch = /bits/ 8 <0x0>; ++ }; ++ ltpi_fan1 { ++ tach-ch = /bits/ 8 <0x1>; ++ }; ++ ltpi_fan2 { ++ tach-ch = /bits/ 8 <0x2>; ++ }; ++ ltpi_fan3 { ++ tach-ch = /bits/ 8 <0x3>; ++ }; ++ ltpi_fan4 { ++ tach-ch = /bits/ 8 <0x4>; ++ }; ++ ltpi_fan5 { ++ tach-ch = /bits/ 8 <0x5>; ++ }; ++ ltpi_fan6 { ++ tach-ch = /bits/ 8 <0x6>; ++ }; ++ ltpi_fan7 { ++ tach-ch = /bits/ 8 <0x7>; ++ }; ++ ltpi_fan8 { ++ tach-ch = /bits/ 8 <0x8>; ++ }; ++ ltpi_fan9 { ++ tach-ch = /bits/ 8 <0x9>; ++ }; ++ ltpi_fan10 { ++ tach-ch = /bits/ 8 <0xA>; ++ }; ++ ltpi_fan11 { ++ tach-ch = /bits/ 8 <0xB>; ++ }; ++ ltpi_fan12 { ++ tach-ch = /bits/ 8 <0xC>; ++ }; ++ ltpi_fan13 { ++ tach-ch = /bits/ 8 <0xD>; ++ }; ++ ltpi_fan14 { ++ tach-ch = /bits/ 8 <0xE>; ++ }; ++ ltpi_fan15 { ++ tach-ch = /bits/ 8 <0xF>; ++ }; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, tmp); -+ return count; -+} ++&sgpios { ++ /delete-property/ gpio-line-names; ++}; + -+static ssize_t ia_cmd_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_gpio { ++ /delete-property/ gpio-line-names; ++ /delete-node/ gpio_17; ++ /delete-node/ gpio_19; ++ /delete-node/ gpio_25; ++ /delete-node/ gpio_53; ++ /delete-node/ gpio_61; ++ /delete-node/ gpio_63; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD)); -+} ++<pi0_adc0 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++}; + -+static ssize_t rnc_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_adc1 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL)); -+} ++<pi0 { ++ i2c-tunneling = <0x0>; ++}; + -+static ssize_t rnc_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; -+ int ret; ++<pi0_i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++<pi0_i3c1 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL, tmp); ++<pi0_i3c3 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ return count; -+} ++<pi0_i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+static ssize_t rbc_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i3c5 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RBC_CTRL)); -+} ++<pi0_i3c6 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06016000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+static ssize_t rbc_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ char opts_str[5]; -+ unsigned int opts_int; -+ int enable, rbc_num, rate, urun_blnk, ret; -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i3c7 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ opts_str[4] = 0; -+ memcpy(opts_str, buf, 4); -+ ret = kstrtouint(opts_str, 16, &opts_int); -+ if (ret) -+ return ret; ++<pi0_i3c8 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06018000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ SYNHW_PRINT("%s %x\n", __func__, opts_int); ++<pi0_i3c9 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ enable = (opts_int >> 12 & 0xf); -+ if (enable > 1) { -+ SYNHW_PRINT("incorrect enable %x\n", enable); -+ return -1; -+ } ++<pi0_i3c10 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601A000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ rbc_num = (opts_int >> 8 & 0xf); -+ if (rbc_num > priv->nisttrng.config.edu_build_cfg0.rbc_channels - 1) { -+ SYNHW_PRINT("incorrect rbc_num %x\n", rbc_num); -+ return -1; -+ } ++<pi0_i3c11 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ rate = (opts_int >> 4 & 0xf); -+ if (rate > 8) { -+ SYNHW_PRINT("incorrect rate %x\n", rate); -+ return -1; -+ } ++<pi0_i3c12 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601C000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ urun_blnk = (opts_int & 0xf); -+ if (urun_blnk > 3) { -+ SYNHW_PRINT("incorrect urun_blnk %x\n", urun_blnk); -+ return -1; -+ } ++<pi0_i3c13 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ SYNHW_PRINT("enable %x rbc_num %x rate %x urun_blnk %x\n", enable, -+ rbc_num, rate, urun_blnk); ++<pi0_i3c14 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601E000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ ret = nisttrng_rbc(&priv->nisttrng, enable, rbc_num, rate, -+ urun_blnk); -+ if (ret) -+ return -1; ++<pi0_i3c15 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ return count; -+} ++&i2c0 { ++ status = "disabled"; ++}; + -+static ssize_t hw_state_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ u32 addr; -+ int i; -+ int tot_char; ++&i2c1 { ++ status = "disabled"; ++}; + -+ addr = 0x20; -+ tot_char = sprintf(buf, "Key = "); -+ for (i = 0; i < 8; i++) { -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, -+ addr + 7 - i); -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, -+ 0x80000000); -+ tot_char += sprintf(buf + tot_char, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_IA_RDATA)); -+ } -+ tot_char += sprintf(buf + tot_char, "\n"); ++&i2c2 { ++ status = "disabled"; ++}; + -+ addr = 0x28; -+ tot_char += sprintf(buf + tot_char, "V = "); -+ for (i = 0; i < 4; i++) { -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, -+ addr + 3 - i); -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, -+ 0x80000000); -+ tot_char += sprintf(buf + tot_char, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_IA_RDATA)); -+ } ++&i2c3 { ++ status = "disabled"; ++}; + -+ tot_char += sprintf(buf + tot_char, "\n"); ++&i2c4 { ++ status = "disabled"; ++}; + -+ return tot_char; -+} ++&i2c5 { ++ status = "disabled"; ++}; + -+static ssize_t max_bits_per_req_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned long tmp; -+ int ret; ++<pi0_i2c0 { ++ status = "okay"; ++}; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++<pi0_i2c1 { ++ status = "okay"; ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtoul(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i2c2 { ++ status = "okay"; ++}; + -+ ret = nisttrng_set_reminder_max_bits_per_req(&priv->nisttrng, -+ tmp); -+ if (ret) -+ return -1; ++<pi0_i2c3 { ++ status = "okay"; ++}; + -+ return count; -+} ++<pi0_i2c4 { ++ status = "okay"; ++}; + -+static ssize_t max_bits_per_req_show(struct device *dev, -+ struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i2c5 { ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08lx\n", -+ priv->nisttrng.counters.max_bits_per_req); -+} ++<pi0_i2c6 { ++ status = "okay"; ++}; + -+static ssize_t max_req_per_seed_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[17]; -+ unsigned long long tmp; -+ int ret; ++<pi0_i2c7 { ++ status = "okay"; ++}; + -+ // string must be at least a 64-bit word in 0 padded hex -+ if (count < 16) -+ return -1; ++<pi0_i2c8 { ++ status = "okay"; ++}; + -+ foo[16] = 0; -+ memcpy(foo, buf, 16); -+ ret = kstrtoull(foo, 16, &tmp); -+ if (ret) -+ return ret; ++<pi0_i2c9 { ++ status = "okay"; ++}; + -+ ret = nisttrng_set_reminder_max_req_per_seed(&priv->nisttrng, -+ tmp); -+ if (ret) -+ return -1; ++<pi0_i2c10 { ++ status = "okay"; ++}; + -+ return count; -+} ++<pi0_i2c11 { ++ status = "okay"; ++}; + -+static ssize_t max_req_per_seed_show(struct device *dev, -+ struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++<pi0_i2c12 { ++ status = "okay"; ++}; + -+ return sprintf(buf, "%08llx\n", -+ priv->nisttrng.counters.max_req_per_seed); -+} ++<pi0_i2c13 { ++ status = "okay"; ++}; + -+static ssize_t collect_ent_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int rep; -+ int i, j; -+ int ret; -+ u32 tmp; -+ int t; -+ -+ t = NIST_TRNG_RETRY_MAX; -+ -+ // Change to TEST mode -+ DEBUG("Change to TEST mode\n"); -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, 0x00000028); -+ // Turn on the noise collect mode -+ DEBUG("Turn on the noise collect mode\n"); -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, 0x80000028); -+ -+ // issue generate entropy command -+ DEBUG("Issue a GEN_NOISE command\n"); -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_GEN_NOISE); -+ -+ // read raw noise -+ // 2 reads if sec_strength is 128 and 3 reads if it is 256 -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) -+ rep = 2; -+ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) -+ rep = 3; -+ -+ for (i = 0; i < rep; i++) { -+ t = NIST_TRNG_RETRY_MAX; -+ tmp = 0; -+ DEBUG("Wait for NOISE_RDY interrupt.\n"); -+ do { -+ tmp = pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_ISTAT); -+ } while (!(tmp & (NIST_TRNG_REG_ISTAT_NOISE_RDY | -+ NIST_TRNG_REG_ISTAT_ALARMS)) && -+ --t); -+ -+ DEBUG("Read NPA_DATAx\n"); -+ for (j = 0; j < 16; j++) { -+ sprintf(buf + 128 * i + 8 * j, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_NPA_DATA0 + j)); -+ } -+ -+ // clear NOISE_RDY IRQ -+ DEBUG("Clear NOISE_RDY interrupt.\n"); -+ ret = nisttrng_wait_on_noise_rdy(&priv->nisttrng); -+ if (ret) -+ return -1; -+ } ++<pi0_i2c14 { ++ status = "okay"; ++}; + -+ DEBUG("Wait for DONE\n"); -+ ret = nisttrng_wait_on_done(&priv->nisttrng); -+ if (ret) -+ return -1; ++<pi0_i2c15 { ++ status = "okay"; ++}; + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++&uart3 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,40 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+static ssize_t collect_ent_nsout_show(struct device *dev, -+ struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int rep; -+ int i; -+ int ret; ++/dts-v1/; + -+ // generate entropy -+ ret = nisttrng_get_entropy_input(&priv->nisttrng, NULL, 0); -+ if (ret) -+ return -1; ++#include "ast2700a1-evb.dts" + -+ // read NS_OUTPUTx -+ // 32 reads if sec_strength is 128 and 48 reads if it is 256 -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) -+ rep = 32; -+ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) -+ rep = 48; ++&fmc { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_fwspi_quad_default>; ++ pinctrl-names = "default"; + -+ for (i = 0; i < rep; i++) { -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, -+ 0x70 + rep - 1 - i); -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, -+ 0x80000000); -+ sprintf(buf + 8 * i, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_IA_RDATA)); -+ } ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "bmc"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++#include "aspeed-evb-flash-layout-256-abr.dtsi" ++ }; + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++ flash@1 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "fmc0:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; + -+static ssize_t nonce_seed_with_df_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ u32 seed[48] = { 0 }; -+ int rep; -+ int i; -+ int ret; ++ flash@2 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "fmc0:2"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; ++}; + -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) -+ rep = 2; -+ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) -+ rep = 3; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,383 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ DEBUG("Number of char in input = %zu\n", count); -+ if (count != (rep * 128)) -+ return -1; ++#include "ast2700a1-evb.dts" ++#include + -+ foo[8] = 0; -+ for (i = 0; i < (rep * 16); i++) { -+ memcpy(foo, buf + i * 8, 8); -+ ret = kstrtouint(foo, 16, (seed + (rep * 16 - 1) - i)); -+ if (ret) -+ return ret; -+ } ++/ { ++ model = "AST2700A1 EVB Test S0 Test"; ++}; + -+ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 1); -+ if (ret) -+ return -1; ++&pcie2 { ++ status = "disabled"; ++}; + -+ return count; -+} ++&mdio2 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+static ssize_t nonce_seed_direct_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ u32 seed[12] = { 0 }; -+ int rep; -+ int i; -+ int ret; ++ ethphy2: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; + -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) -+ rep = 2; -+ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) -+ rep = 3; ++&sgmii { ++ status = "okay"; ++}; + -+ DEBUG("Number of char in input = %zu\n", count); -+ if (count != (rep * 32)) -+ return -1; ++&mac2 { ++ status = "okay"; + -+ foo[8] = 0; -+ for (i = 0; i < (rep * 4); i++) { -+ memcpy(foo, buf + i * 8, 8); -+ ret = kstrtouint(foo, 16, (seed + (rep * 4 - 1) - i)); -+ if (ret) -+ return ret; -+ } ++ phy-mode = "sgmii"; ++ phy-handle = <ðphy2>; ++}; + -+ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 0); -+ if (ret) -+ return -1; ++&sdio_controller { ++ status = "disabled"; ++}; + -+ return count; -+} ++&sdhci { ++ status = "disabled"; ++}; + -+static ssize_t instantiate_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char opts_str[101]; -+ unsigned int opts_int; -+ int req_sec_strength = 256; -+ int pred_resist = 1; -+ bool ps_exists = 0; -+ u32 ps[12]; -+ unsigned int ps_length; -+ int i; -+ int ret; ++&espi1 { ++ status = "okay"; ++ perif-dma-mode; ++#if 0 //TODO: No enough memory for espi1 MMBI ++ perif-mmbi-enable; ++ perif-mmbi-src-addr = <0x0 0xa8000000>; ++ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; ++ perif-mmbi-instance-num = <0x1>; ++#endif ++ perif-mcyc-enable; ++ perif-mcyc-src-addr = <0x0 0x98000000>; ++ perif-mcyc-size = <0x0 0x10000>; ++ oob-dma-mode; ++ flash-dma-mode; ++}; + -+ /* First 3 digits: -+ * they have to be 0 or 1 -+ * 2-1-0 --> 2: predictoin resistance, 1: security strength, 0: personilizatoin string existence -+ */ -+ opts_str[3] = 0; -+ memcpy(opts_str, buf, 3); -+ ret = kstrtouint(opts_str, 2, &opts_int); -+ if (ret) -+ return ret; ++&can0 { ++ status = "disabled"; ++}; + -+ if (((opts_str[0] != '0') && (opts_str[0] != '1')) || -+ ((opts_str[1] != '0') && (opts_str[1] != '1')) || -+ ((opts_str[2] != '0') && (opts_str[2] != '1'))) { -+ SYNHW_PRINT("Invalid input options: First 3 digits can only be 1 or 0\n"); -+ return -1; -+ } ++// S0 use 0x10 as its slave address ++&i2c0 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (opts_int & 1) -+ ps_exists = 1; -+ else -+ ps_exists = 0; ++&i2c1 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (opts_int & 2) -+ req_sec_strength = 256; -+ else -+ req_sec_strength = 128; ++&i2c2 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (opts_int & 4) -+ pred_resist = 1; -+ else -+ pred_resist = 0; ++&i2c3 { ++ clock-frequency = <1000000>; ++ debounce-level = <6>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ /* check input option length */ -+ if (!ps_exists) { -+ if (count != 3) { -+ SYNHW_PRINT("Invalid input options: If personilization string does not exist, options has to be 3 char.\n"); -+ return -1; -+ } -+ } else { -+ if (req_sec_strength == 128) { -+ if (count != 64 + 4) { // +4 for options and "-" -+ SYNHW_PRINT("Invalid input options: If personilization string exists and security strength is 128-bit, options has to be 68 char (not %zu char).\n", -+ count); -+ return -1; -+ } -+ } else if (req_sec_strength == 256) { -+ if (count != -+ 96 + 4) { // +4 for options and "-", +1 because of the termination char that count includes -+ SYNHW_PRINT("Invalid input options: If personilization string exists and security strength is 256-bit, options has to be 100 char (not %zu char).\n", -+ count); -+ return -1; -+ } -+ } else { -+ SYNHW_PRINT("Invalid input options\n"); -+ return -1; -+ } -+ } ++&i2c4 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ /* Personilization string */ -+ for (i = 0; i < 12; i++) -+ ps[i] = 0; ++&i2c5 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (req_sec_strength == 128) -+ ps_length = 64; -+ else if (req_sec_strength == 256) -+ ps_length = 96; -+ else -+ SYNHW_PRINT("Invalid security strength\n"); -+ -+ if (ps_exists) { -+ opts_str[1] = 0; -+ memcpy(opts_str, buf + 3, 1); -+ -+ if (opts_str[0] == '-') { -+ opts_str[8] = 0; -+ for (i = 0; i < ps_length / 8; i++) { -+ memcpy(opts_str, buf + 4 + i * 8, 8); -+ ret = kstrtouint(opts_str, 16, -+ ps + (ps_length / 8 - 1) - i); -+ if (ret) -+ return ret; -+ } -+ } else { -+ SYNHW_PRINT("4th character of input has to be \"-\" when personilization string exists\n"); -+ } ++&i2c6 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ ret = nisttrng_instantiate(&priv->nisttrng, -+ req_sec_strength, pred_resist, -+ ps); -+ if (ret) -+ return -1; ++&i2c7 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ } else { -+ ret = nisttrng_instantiate(&priv->nisttrng, -+ req_sec_strength, pred_resist, -+ NULL); -+ if (ret) -+ return -1; -+ } ++&i2c8 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ return count; -+} ++&i2c9 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+static ssize_t uninstantiate_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++&i2c10 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ nisttrng_uninstantiate(&priv->nisttrng); ++&i2c11 { ++ clock-frequency = <1000000>; ++ debounce-level = <6>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ return count; -+} ++&i2c12 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+static ssize_t reseed_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char opts_str[100]; -+ unsigned int opts_int; -+ int pred_resist = 1; -+ bool addin_exists = 0; -+ u32 addin[12]; -+ unsigned int addin_length; -+ int i; -+ int ret; ++&i2c13 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ /* First 2 digits: -+ * they have to be 0 or 1 -+ * 1-0 --> 1: predictoin resistance, 0: additional input string existence -+ */ -+ opts_str[2] = 0; -+ memcpy(opts_str, buf, 2); -+ ret = kstrtouint(opts_str, 2, &opts_int); -+ if (ret) -+ return ret; ++&i2c14 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (((opts_str[0] != '0') && (opts_str[0] != '1')) || -+ ((opts_str[1] != '0') && (opts_str[1] != '1'))) { -+ SYNHW_PRINT("Invalid input options: First 2 digits can only be 1 or 0\n"); -+ return -1; -+ } ++&i2c15 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (opts_int & 1) -+ addin_exists = 1; -+ else -+ addin_exists = 0; ++&i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ if (opts_int & 2) -+ pred_resist = 1; -+ else -+ pred_resist = 0; ++&i3c1 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06011000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* check input option length */ -+ if (!addin_exists) { -+ if (count != 2) { -+ SYNHW_PRINT("Invalid input options: If additional input does not exist, options has to be 2 char.\n"); -+ return -1; -+ } -+ } else { -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) { -+ if (count != 64 + 3) { // +3 for options and "-" -+ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 128-bit, options has to be 67 char.\n"); -+ return -1; -+ } -+ } else if (priv->nisttrng.status.sec_strength == -+ SEC_STRNT_AES256) { -+ if (count != 96 + 3) { // +3 for options and "-" -+ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 256-bit, options has to be 99 char.\n"); -+ return -1; -+ } -+ } else { -+ SYNHW_PRINT("Invalid input options\n"); -+ return -1; -+ } -+ } ++&i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* Additional input */ -+ for (i = 0; i < 12; i++) -+ addin[i] = 0; ++&i3c3 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06013000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) -+ addin_length = 64; -+ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) -+ addin_length = 96; -+ else -+ SYNHW_PRINT("Invalid security strength\n"); -+ -+ if (addin_exists) { -+ opts_str[1] = 0; -+ memcpy(opts_str, buf + 2, 1); -+ -+ if (opts_str[0] == '-') { -+ opts_str[8] = 0; -+ for (i = 0; i < addin_length / 8; i++) { -+ memcpy(opts_str, buf + 3 + i * 8, 8); -+ ret = kstrtouint(opts_str, 16, addin + (addin_length / 8 - 1) - i); -+ if (ret) -+ return ret; -+ } -+ } else { -+ SYNHW_PRINT("3rd character of input has to be \"-\" when additional input exists\n"); -+ } ++&i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, -+ addin); -+ if (ret) -+ return -1; ++&i3c5 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06015000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ } else { -+ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, -+ NULL); -+ if (ret) -+ return -1; -+ } ++&i3c6 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06016000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ return count; -+} ++&i3c7 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06017000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+static ssize_t generate_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char opts_str[101]; -+ unsigned int opts_int; -+ int req_sec_strength = 128; -+ int pred_resist = 1; -+ bool addin_exists = 0; -+ unsigned char out[num_gen_bytes]; -+ u32 addin[12]; -+ unsigned int addin_length; -+ int i; -+ int ret; ++&i3c8 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06018000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* First 3 digits: -+ * they have to be 0 or 1 -+ * 2-1-0 --> 2: predictoin resistance, 1: security strength, 0: additional input string existence -+ */ -+ opts_str[3] = 0; -+ memcpy(opts_str, buf, 3); -+ ret = kstrtouint(opts_str, 2, &opts_int); -+ if (ret) -+ return ret; ++&i3c9 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06019000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ if (((opts_str[0] != '0') && (opts_str[0] != '1')) || -+ ((opts_str[1] != '0') && (opts_str[1] != '1')) || -+ ((opts_str[2] != '0') && (opts_str[2] != '1'))) { -+ SYNHW_PRINT("Invalid input options: First 3 digits can only be 1 or 0\n"); -+ return -1; -+ } ++&i3c10 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601A000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ if (opts_int & 1) -+ addin_exists = 1; -+ else -+ addin_exists = 0; ++&i3c11 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601B000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ if (opts_int & 2) -+ req_sec_strength = 256; -+ else -+ req_sec_strength = 128; ++&i3c12 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601C000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ if (opts_int & 4) -+ pred_resist = 1; -+ else -+ pred_resist = 0; ++&i3c13 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601D000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* check input option length */ -+ if (!addin_exists) { -+ if (count != 3) { -+ SYNHW_PRINT("Invalid input options: If additional input does not exist, options has to be 3 char.\n"); -+ return -1; -+ } -+ } else { -+ if (req_sec_strength == 128) { -+ if (count != 64 + 4) { // +4 for options and "-" -+ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 128-bit, options has to be 68 char.\n"); -+ return -1; -+ } -+ } else if (req_sec_strength == 256) { -+ if (count != 96 + 4) { // +4 for options and "-" -+ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 256-bit, options has to be 100 char.\n"); -+ return -1; -+ } -+ } else { -+ SYNHW_PRINT("Invalid input options\n"); -+ return -1; -+ } -+ } ++&i3c14 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601E000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* Additional input */ -+ for (i = 0; i < 12; i++) -+ addin[i] = 0; ++&i3c15 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601F000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,485 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ if (req_sec_strength == 128) -+ addin_length = 64; -+ else if (req_sec_strength == 256) -+ addin_length = 96; -+ else -+ SYNHW_PRINT("Invalid security strength\n"); -+ -+ if (addin_exists) { -+ opts_str[1] = 0; -+ memcpy(opts_str, buf + 3, 1); -+ -+ if (opts_str[0] == '-') { -+ opts_str[8] = 0; -+ for (i = 0; i < addin_length / 8; i++) { -+ memcpy(opts_str, buf + 4 + i * 8, 8); -+ ret = kstrtouint(opts_str, 16, addin + (addin_length / 8 - 1) - i); -+ if (ret) -+ return ret; -+ } -+ } else { -+ SYNHW_PRINT("4th character of input has to be \"-\" when additional input exists\n"); -+ } ++#include "ast2700a1-evb.dts" ++#include + -+ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, -+ num_gen_bytes, req_sec_strength, -+ pred_resist, addin); -+ if (ret) -+ return -1; ++/ { ++ model = "AST2700A1 EVB Test S1 Test"; ++}; + -+ } else { -+ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, -+ num_gen_bytes, req_sec_strength, -+ pred_resist, NULL); -+ if (ret) -+ return -1; -+ } ++&bmc_dev0 { ++ status = "disabled"; ++}; + -+ /* store the result */ -+ memcpy(priv->rand_out, out, sizeof(out)); ++&xdma0 { ++ status = "disabled"; ++}; + -+ return count; -+} ++&pcie_vuart0 { ++ status = "disabled"; ++}; + -+static ssize_t generate_pub_vtrng_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char opts_str[2]; -+ unsigned int opts_int; -+ unsigned char out[num_gen_bytes]; -+ int ret; ++&pcie_vuart1 { ++ status = "disabled"; ++}; + -+ opts_str[1] = 0; -+ memcpy(opts_str, buf, 1); -+ ret = kstrtouint(opts_str, 16, &opts_int); -+ if (ret) -+ return ret; ++&pcie_lpc0_kcs0 { ++ status = "disabled"; ++}; + -+ SYNHW_PRINT("%s %d %d %d %d\n", __func__, opts_str[0], -+ priv->nisttrng.config.edu_build_cfg0.public_vtrng_channels, -+ opts_str[1], opts_int); ++&pcie_lpc0_kcs1 { ++ status = "disabled"; ++}; + -+ ret = nisttrng_generate_public_vtrng(&priv->nisttrng, -+ (u32 *)out, -+ num_gen_bytes, opts_int); -+ if (ret) -+ return -1; ++&pcie_lpc0_kcs2 { ++ status = "disabled"; ++}; + -+ memcpy(priv->rand_out, out, sizeof(out)); ++&pcie_lpc0_kcs3 { ++ status = "disabled"; ++}; + -+ return count; -+} ++&pcie_lpc0_ibt { ++ status = "disabled"; ++}; + -+/* rand_out_show displays last generated random number (num_gen_bytes number of bytes), not just the last block. */ -+static ssize_t rand_out_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ unsigned int i, j; -+ unsigned long rand; -+ bool all_zero = true; ++&pcie0_mmbi0 { ++ status = "disabled"; ++}; + -+ /* If all bits of the rand_reg register are 0, display 0 */ -+ for (i = 0; i < 4; i++) { -+ rand = pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_RAND0 + -+ (3 - i)); -+ if (rand != 0) { -+ all_zero = false; -+ break; -+ } -+ } ++&pcie0 { ++ status = "okay"; ++}; + -+ if (all_zero) { -+ sprintf(buf + 2 * i, "%02x", 0); -+ } else { -+ for (i = 0; i < (num_gen_bytes / 16); i++) { -+ for (j = 0; j < 16; j++) { -+ sprintf(buf + 2 * (i * 16 + j), "%02x", -+ priv->rand_out[(i + 1) * 16 - 1 - j]); -+ } -+ } -+ j = 0; -+ while (i * 16 + j < num_gen_bytes) { -+ sprintf(buf + 2 * (i * 16 + j), "%02x", -+ priv->rand_out[num_gen_bytes - 1 - j]); -+ j++; -+ } -+ } ++&bmc_dev1 { ++ status = "disabled"; ++}; + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++&xdma1 { ++ status = "disabled"; ++}; + -+/* rand_out_vtrng_show displays last generated random number (num_gen_bytes number of bytes), not just the last block. */ -+static ssize_t rand_out_vtrng_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ unsigned int i, j; ++&pcie_vuart2 { ++ status = "disabled"; ++}; + -+ /* If all bits of the rand_reg register are 0, display 0 */ ++&pcie_vuart3 { ++ status = "disabled"; ++}; + -+ for (i = 0; i < (num_gen_bytes / 16); i++) { -+ for (j = 0; j < 16; j++) { -+ sprintf(buf + 2 * (i * 16 + j), "%02x", -+ priv->rand_out[(i + 1) * 16 - 1 - j]); -+ } -+ } ++&pcie_lpc1_kcs0 { ++ status = "disabled"; ++}; + -+ j = 0; -+ while (i * 16 + j < num_gen_bytes) { -+ sprintf(buf + 2 * (i * 16 + j), "%02x", -+ priv->rand_out[num_gen_bytes - 1 - j]); -+ j++; -+ } ++&pcie_lpc1_kcs1 { ++ status = "disabled"; ++}; + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++&pcie_lpc1_kcs2 { ++ status = "disabled"; ++}; + -+static ssize_t kat_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int ret; ++&pcie_lpc1_kcs3 { ++ status = "disabled"; ++}; + -+ if (sysfs_streq(buf, "full")) { -+ ret = nisttrng_full_kat(&priv->nisttrng); -+ if (ret) -+ return -1; ++&pcie_lpc1_ibt { ++ status = "disabled"; ++}; + -+ } else if (sysfs_streq(buf, "00")) { -+ ret = nisttrng_kat(&priv->nisttrng, 0, 0); -+ if (ret) -+ return -1; ++&pcie1_mmbi4 { ++ status = "disabled"; ++}; + -+ } else if (sysfs_streq(buf, "01")) { -+ ret = nisttrng_kat(&priv->nisttrng, 0, 1); -+ if (ret) -+ return -1; ++&pcie1 { ++ status = "okay"; ++}; + -+ } else if (sysfs_streq(buf, "10")) { -+ ret = nisttrng_kat(&priv->nisttrng, 1, 0); -+ if (ret) -+ return -1; ++&sdio_controller { ++ status = "disabled"; ++}; + -+ } else if (sysfs_streq(buf, "11")) { -+ ret = nisttrng_kat(&priv->nisttrng, 1, 1); -+ if (ret) -+ return -1; ++&sdhci { ++ status = "disabled"; ++}; + -+ } else { -+ ret = nisttrng_full_kat(&priv->nisttrng); -+ if (ret) -+ return -1; -+ } ++&espi1 { ++ status = "okay"; ++ perif-dma-mode; ++#if 0 // TODO: No enough memory for espi1 MMBI ++ perif-mmbi-enable; ++ perif-mmbi-src-addr = <0x0 0xa8000000>; ++ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; ++ perif-mmbi-instance-num = <0x1>; ++#endif ++ perif-mcyc-enable; ++ perif-mcyc-src-addr = <0x0 0x98000000>; ++ perif-mcyc-size = <0x0 0x10000>; ++ oob-dma-mode; ++ flash-dma-mode; ++}; + -+ return count; -+} ++&can0 { ++ status = "disabled"; ++}; + -+static void str_to_384_bit(char *buf, u32 *out) -+{ -+ char foo[9]; -+ int i; -+ int ret; ++// S1 use 0x12 as its slave address ++&i2c0 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ foo[8] = 0; -+ for (i = 0; i < 12; i++) { -+ memcpy(foo, buf + i * 8, 8); -+ ret = kstrtouint(foo, 16, out + 11 - i); -+ } -+} ++&i2c1 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+/* This attribute is only for test purpuses */ -+static ssize_t test_attr_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int i; -+ int err; -+ u32 addin[12]; -+ u32 ps[12]; -+ char *out; -+ -+ char buf_seed1[96] = -+ "c54805274bde00aa5289e0513579019707666d2fa7a1c8908865891c87c0c652335a4d3cc415bc30742b164647f8820f"; -+ char buf_ps1[96] = -+ "d63fb5afa2101fa4b8a6c3b89d9c250ac728fc1ddad0e7585b5d54728ed20c2f940e89155596e3b963635b6d6088164b"; -+ char buf_addin1[96] = -+ "744bfae3c23a5cc9a3b373b6c50795068d35eb8a339746ac810d16f864e880061082edf9d2687c211960aa83400f85f9"; -+ char buf_seed2[96] = -+ "b2ad31d1f20dcf30dd526ec9156c07f270216bdb59197325bab180675929888ab699c54fb21819b7d921d6346bff2f7f"; -+ char buf_addin2[96] = -+ "ad55c682962aa4fe9ebc227c9402e79b0aa7874844d33eaee7e2d15baf81d9d33936e4d93f28ad109657b512aee115a5"; -+ char buf_seed3[96] = -+ "eca449048d26fd38f8ca435237dce66eadec7069ee5dd0b70084b819a711c0820a7556bbd0ae20f06e5169278b593b71"; -+ u32 tmp[12]; -+ -+ for (i = 0; i < 12; i++) -+ addin[i] = i; -+ -+ for (i = 0; i < 12; i++) -+ ps[i] = i + 100; -+ -+ /* SDK doc example - Prediction Resistance not available, no Reseed */ -+ err = nisttrng_uninstantiate(&priv->nisttrng); -+ if (err && err != CRYPTO_NOT_INSTANTIATED) -+ return -1; ++&i2c2 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (nisttrng_instantiate(&priv->nisttrng, 128, 0, ps) < 0) -+ return -1; ++&i2c3 { ++ clock-frequency = <1000000>; ++ debounce-level = <6>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ out = kmalloc(10, GFP_KERNEL); -+ if (nisttrng_generate(&priv->nisttrng, out, 10, 128, 0, addin) < 0) -+ return -1; ++&i2c4 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ DEBUG("----- Generate 10 bytes\n"); -+ for (i = 0; i < 10; i++) -+ DEBUG("%02x", out[i]); ++&i2c5 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ DEBUG("\n"); -+ kfree(out); ++&i2c6 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ out = kmalloc(512, GFP_KERNEL); -+ if (nisttrng_generate(&priv->nisttrng, out, 512, 128, 0, addin) < 0) -+ return -1; ++&i2c7 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ DEBUG("----- Generate 512 bytes\n"); -+ for (i = 0; i < 512; i++) -+ DEBUG("%02x", out[i]); ++&i2c8 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ DEBUG("\n"); -+ kfree(out); ++&i2c9 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ out = kmalloc(41, GFP_KERNEL); -+ if (nisttrng_generate(&priv->nisttrng, out, 41, 128, 0, addin) < 0) -+ return -1; ++&i2c10 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ DEBUG("----- Generate 41 bytes\n"); -+ for (i = 0; i < 41; i++) -+ DEBUG("%02x", out[i]); ++&i2c11 { ++ clock-frequency = <1000000>; ++ debounce-level = <6>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ DEBUG("\n"); -+ kfree(out); ++&i2c12 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ err = nisttrng_uninstantiate(&priv->nisttrng); -+ if (err < 0 && err != CRYPTO_NOT_INSTANTIATED) -+ return -1; ++&i2c13 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ /* SDK doc example - DRBG Validation */ -+ err = nisttrng_uninstantiate(&priv->nisttrng); -+ if (err && err != CRYPTO_NOT_INSTANTIATED) -+ return -1; ++&i2c14 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "buff"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ if (nisttrng_set_nonce_mode(&priv->nisttrng, 1) < 0) -+ return -1; ++&i2c15 { ++ clock-frequency = <1000000>; ++ debounce-level = <4>; ++ status = "okay"; ++ multi-master; ++ mctp-controller; ++ aspeed,transfer-mode = "dma"; ++ mctp@12 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; + -+ out = kmalloc(64, GFP_KERNEL); -+ str_to_384_bit(buf_seed1, tmp); -+ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) -+ return -1; ++&i3c0 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ str_to_384_bit(buf_ps1, tmp); -+ if (nisttrng_instantiate(&priv->nisttrng, 256, 1, tmp) < 0) -+ return -1; ++&i3c1 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ str_to_384_bit(buf_seed2, tmp); -+ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) -+ return -1; ++&i3c2 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ str_to_384_bit(buf_addin1, tmp); -+ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) -+ return -1; ++&i3c3 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ str_to_384_bit(buf_seed3, tmp); -+ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) -+ return -1; ++&i3c4 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ str_to_384_bit(buf_addin2, tmp); -+ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) -+ return -1; ++&i3c5 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ memcpy(priv->rand_out, out, 64); ++&i3c6 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ return count; -+} ++&i3c7 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+static DEVICE_ATTR_RO(ckr); -+static DEVICE_ATTR_RO(features); -+static DEVICE_ATTR_RW(secure); -+static DEVICE_ATTR_RW(nonce); -+static DEVICE_ATTR_RW(sec_strength); -+ -+static DEVICE_ATTR_RW(mode_reg); -+static DEVICE_ATTR_RW(smode_reg); -+static DEVICE_ATTR_RW(alarm_reg); -+static DEVICE_ATTR_RO(rand_reg); -+static DEVICE_ATTR_RO(rand_out); -+static DEVICE_ATTR_RO(rand_out_vtrng); -+static DEVICE_ATTR_RW(seed_reg); -+static DEVICE_ATTR_RW(npa_data_reg); -+static DEVICE_ATTR_RW(ctrl_reg); -+static DEVICE_ATTR_RW(istat_reg); -+static DEVICE_ATTR_RO(stat_reg); -+static DEVICE_ATTR_RW(rnc_reg); -+static DEVICE_ATTR_RW(rbc_reg); -+ -+static DEVICE_ATTR_RW(ia_wdata_reg); -+static DEVICE_ATTR_RO(ia_rdata_reg); -+static DEVICE_ATTR_RW(ia_addr_reg); -+static DEVICE_ATTR_RW(ia_cmd_reg); -+static DEVICE_ATTR_RO(hw_state); -+ -+static DEVICE_ATTR_RO(collect_ent); -+static DEVICE_ATTR_RO(collect_ent_nsout); -+static DEVICE_ATTR_WO(nonce_seed_with_df); -+static DEVICE_ATTR_WO(nonce_seed_direct); -+static DEVICE_ATTR_WO(instantiate); -+static DEVICE_ATTR_WO(uninstantiate); -+static DEVICE_ATTR_WO(reseed); -+static DEVICE_ATTR_WO(generate); -+static DEVICE_ATTR_WO(generate_pub_vtrng); -+static DEVICE_ATTR_WO(kat); -+ -+static DEVICE_ATTR_RW(max_bits_per_req); -+static DEVICE_ATTR_RW(max_req_per_seed); -+ -+static DEVICE_ATTR_WO(test_attr); -+ -+static const struct attribute_group nisttrng_attr_group = { -+ .attrs = -+ (struct attribute *[]){ -+ &dev_attr_ckr.attr, -+ //&dev_attr_stepping.attr, -+ &dev_attr_features.attr, &dev_attr_secure.attr, -+ &dev_attr_nonce.attr, &dev_attr_sec_strength.attr, -+ -+ &dev_attr_mode_reg.attr, &dev_attr_smode_reg.attr, -+ &dev_attr_alarm_reg.attr, &dev_attr_rand_reg.attr, -+ &dev_attr_rand_out.attr, &dev_attr_rand_out_vtrng.attr, -+ &dev_attr_seed_reg.attr, &dev_attr_npa_data_reg.attr, -+ &dev_attr_ctrl_reg.attr, &dev_attr_istat_reg.attr, -+ &dev_attr_stat_reg.attr, &dev_attr_rnc_reg.attr, -+ &dev_attr_rbc_reg.attr, -+ -+ &dev_attr_ia_wdata_reg.attr, -+ &dev_attr_ia_rdata_reg.attr, &dev_attr_ia_addr_reg.attr, -+ &dev_attr_ia_cmd_reg.attr, &dev_attr_hw_state.attr, -+ -+ &dev_attr_collect_ent.attr, -+ &dev_attr_collect_ent_nsout.attr, -+ &dev_attr_nonce_seed_with_df.attr, -+ &dev_attr_nonce_seed_direct.attr, -+ &dev_attr_instantiate.attr, -+ &dev_attr_uninstantiate.attr, &dev_attr_reseed.attr, -+ &dev_attr_generate.attr, -+ &dev_attr_generate_pub_vtrng.attr, &dev_attr_kat.attr, -+ -+ &dev_attr_max_bits_per_req.attr, -+ &dev_attr_max_req_per_seed.attr, -+ -+ &dev_attr_test_attr.attr, NULL }, -+}; -+ -+static int nisttrng_self_test(struct nist_trng_state *nist_trng) -+{ -+ u32 seed[16], out[4], x, y; -+ -+ static const u32 exp128[10][4] = { -+ { 0x5db79bb2, 0xc3a0df1e, 0x099482b6, -+ 0xc319981e }, // The 1st generated output -+ { 0xb344d301, 0xdbd97ca0, 0x6e66e668, -+ 0x0bcd4625 }, // The 2nd generate output -+ { 0xec553f18, 0xa0e5c3cb, 0x752c03c2, -+ 0x5e7b04f7 }, // The 3rd generate output -+ { 0xcfe23e6e, 0x5302edc2, 0xdbf7b05b, -+ 0x2c817c0f }, // The 4th generate output -+ { 0xbd5a8726, 0x028c43d0, 0xb77ac4e3, -+ 0x0844ba2c }, // The 5th generate output -+ { 0xa63b4c0e, 0x8d11d0ba, 0x08b5a10f, -+ 0xab731aff }, // The 6th generate output -+ { 0xb7b56a2f, 0x1d84d1f0, 0xe48d1a0a, -+ 0x43a010a6 }, // The 7th generate output -+ { 0xcf66439d, 0xc937451d, 0x75c34d20, -+ 0x21a21398 }, // The 8th generate output -+ { 0xcb6f0a57, 0x5ff34705, 0x08838e49, -+ 0x21137614 }, // The 9th generate output -+ { 0x61c48b24, 0x25c18d29, 0xc6005e4e, -+ 0xae3b0389 }, // The 10th generate output -+ }; -+ -+ static const u32 exp256[10][4] = { -+ { 0x1f1a1441, 0xa0865ece, 0x9ff8d5b9, -+ 0x3f78ace6 }, // The 1st generated output -+ { 0xf8190a86, 0x6d6ded2a, 0xc4d0e9bf, -+ 0x24dab55c }, // The 2nd generate output -+ { 0xd3948b74, 0x3dfea516, 0x9c3b86a2, -+ 0xeb184b41 }, // The 3rd generate output -+ { 0x2eb82ab6, 0x2aceefda, 0xc0cf6a5f, -+ 0xa45cb333 }, // The 4th generate output -+ { 0xa49b1c7b, 0x5b51bac7, 0x7586770b, -+ 0x8cb2c392 }, // The 5th generate output -+ { 0x3f3ba09d, 0xa2c9ad29, 0x9687fb8f, -+ 0xa5ae3fd5 }, // The 6th generate output -+ { 0x11dd1076, 0xe37e86cb, 0xced0220a, -+ 0x00448c4f }, // The 7th generate output -+ { 0x955a5e52, 0x84ee38b1, 0xb3271e5f, -+ 0x097751e3 }, // The 8th generate output -+ { 0x5cd73ba8, 0xd8a36a1e, 0xa8a2d7c3, -+ 0xa96de048 }, // The 9th generate output -+ { 0xfb374c63, 0x827b85fa, 0x244e0c7a, -+ 0xa09afd39 }, // The 10th generate output -+ }; -+ -+ int ret, enable, rate, urun; -+ u32 tmp; -+ -+ for (x = 0; x < 16; x++) -+ seed[x] = 0x12345679 * (x + 1); -+ -+ DEBUG("Doing a self-test with security strength of 128\n"); -+ ret = nisttrng_uninstantiate(nist_trng); -+ if (ret && ret != CRYPTO_NOT_INSTANTIATED) -+ goto ERR; -+ -+ //if ((ret = nisttrng_set_secure_mode(nist_trng, 0))) { goto ERR; } -+ ret = nisttrng_set_nonce_mode(nist_trng, 1); -+ if (ret) -+ goto ERR; ++&i3c8 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ ret = nisttrng_set_sec_strength(nist_trng, 128); -+ if (ret) -+ goto ERR; ++&i3c9 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); -+ if (ret) -+ goto ERR; ++&i3c10 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ ret = nisttrng_instantiate(nist_trng, 128, 0, NULL); -+ if (ret) -+ goto ERR; ++&i3c11 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ if (nist_trng->config.build_cfg0.edu_present) { -+ ret = nisttrng_wait_fifo_full(nist_trng); -+ if (ret) -+ goto ERR; -+ } ++&i3c12 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ ret = nisttrng_generate(nist_trng, out, 16, 128, 0, NULL); -+ if (ret) -+ goto ERR; ++&i3c13 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ if (nist_trng->config.features.extra_ps_present) { -+ DEBUG("skip KAT with extra_ps_present\n"); -+ } else { -+ DEBUG("nist_trng: AES-128 Self-test output: "); -+ for (x = 0; x < 4; x++) -+ DEBUG("0x%08lx ", (unsigned long)out[x]); -+ -+ if (nist_trng->config.build_cfg0.edu_present) { -+ if (nist_trng->config.edu_build_cfg0 -+ .esm_channel) { //if esm_channel is available the first random number goes to esm -+ for (x = 0; x < 4; x++) { -+ if (out[x] != exp128[1][x]) -+ ret = 1; -+ } -+ } -+ } else { -+ for (x = 0; x < 4; x++) { -+ if (out[x] != exp128[0][x]) -+ ret = 1; -+ } -+ } ++&i3c14 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ if (ret) { -+ SYNHW_PRINT("... FAILED comparison\n"); -+ ret = -1; -+ goto ERR; -+ } else { -+ DEBUG("... PASSED\n"); -+ } -+ } ++&i3c15 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ // if edu is available check all the pvtrng's -+ if (nist_trng->config.build_cfg0.edu_present) { -+ for (x = 0; -+ x < nist_trng->config.edu_build_cfg0.public_vtrng_channels; -+ x++) { -+ DEBUG("vtrng %d\n", x); -+ ret = nisttrng_generate_public_vtrng(nist_trng, out, 16, x); -+ if (ret) -+ goto ERR; ++&sgpios { ++ status = "disabled"; ++}; + -+ for (y = 0; y < 4; y++) { -+ DEBUG("0x%08lx ", (unsigned long)out[y]); -+ if (out[y] != exp128[x + 2][y]) -+ ret = 1; -+ } -+ if (ret) { -+ SYNHW_PRINT("... FAILED comparison\n"); -+ ret = -1; -+ goto ERR; -+ } else { -+ DEBUG("... PASSED\n"); -+ } -+ } -+ } -+ // if edu is available empty the fifo before creating the new instance with strength of 256 -+ if (nist_trng->config.build_cfg0.edu_present) { -+ nisttrng_rnc(nist_trng, -+ NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE); -+ tmp = NIST_TRNG_REG_ISTAT_DONE; -+ //always clear the busy bit after disabling RNC -+ pdu_io_write32(nist_trng->base + NIST_TRNG_REG_ISTAT, tmp); -+ tmp = pdu_io_read32(nist_trng->base + NIST_TRNG_REG_ISTAT); -+ do { -+ ret = nisttrng_generate_public_vtrng(nist_trng, out, 16, 0); -+ if (ret) -+ goto ERR; ++&mac0 { ++ status = "okay"; + -+ tmp = pdu_io_read32(nist_trng->base + -+ NIST_TRNG_EDU_STAT); ++ phy-mode = "rmii"; ++ use-ncsi; + -+ } while (!NIST_TRNG_EDU_STAT_FIFO_EMPTY(tmp)); -+ } ++ pinctrl-names = "default"; ++ /* If you want to use RMII0 RCLKO as internal clock for RMII, ++ * add &pinctrl_rmii0_rclko_default in pinctrl-0. ++ */ ++ pinctrl-0 = <&pinctrl_rmii0_default>; ++}; + -+ if (nist_trng->config.features.drbg_arch == AES256) { -+ // test AES-256 mode -+ DEBUG("Doing a self-test with security strength of 256\n"); -+ ret = nisttrng_uninstantiate(nist_trng); -+ if (ret && ret != CRYPTO_NOT_INSTANTIATED) -+ goto ERR; ++&mac1 { ++ status = "okay"; + -+ ret = nisttrng_set_nonce_mode(nist_trng, 1); -+ if (ret) -+ goto ERR; ++ phy-mode = "rmii"; ++ use-ncsi; + -+ ret = nisttrng_set_sec_strength(nist_trng, 256); -+ if (ret) -+ goto ERR; ++ pinctrl-names = "default"; ++ /* If you want to use RMII1 RCLKO as internal clock for RMII, ++ * add &pinctrl_rmii1_rclko_default in pinctrl-0. ++ */ ++ pinctrl-0 = <&pinctrl_rmii1_default>; ++}; + -+ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); -+ if (ret) -+ goto ERR; ++&syscon1 { ++ mac0-clk-delay = <0 0 ++ 0 0 ++ 0 0>; ++ mac1-clk-delay = <0 0 ++ 0 0 ++ 0 0>; ++}; + -+ ret = nisttrng_instantiate(nist_trng, 256, 0, NULL); -+ if (ret) -+ goto ERR; ++&vhuba0 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_usb2ad0_default>; ++}; + -+ ret = nisttrng_generate(nist_trng, out, 16, 256, 0, NULL); -+ if (ret) -+ goto ERR; ++&vhubb0 { ++ status = "okay"; ++}; + -+ if (nist_trng->config.features.extra_ps_present) { -+ DEBUG("skip KAT with extra_ps_present\n"); -+ } else { -+ DEBUG("nist_trng: AES-256 Self-test output: "); -+ for (x = 0; x < 4; x++) -+ DEBUG("0x%08lx ", (unsigned long)out[x]); ++&vhubb1 { ++ status = "disabled"; ++}; + -+ for (x = 0; x < 4; x++) { -+ if (out[x] != exp256[0][x]) -+ ret = 1; -+ } -+ if (ret) { -+ SYNHW_PRINT("... FAILED comparison\n"); -+ ret = -1; -+ goto ERR; -+ } else { -+ DEBUG("... PASSED\n"); -+ } -+ } -+ } ++&vhubc { ++ status = "disabled"; ++}; + -+ // if edu is available check all the pvtrng's -+ if (nist_trng->config.build_cfg0.edu_present) { -+ for (x = 0; -+ x < nist_trng->config.edu_build_cfg0.public_vtrng_channels; -+ x++) { -+ DEBUG("vtrng 256 %d\n", x); -+ ret = nisttrng_generate_public_vtrng(nist_trng, out, 16, x); -+ if (ret) -+ goto ERR; ++&vhubd { ++ status = "okay"; ++}; + -+ for (y = 0; y < 4; y++) { -+ DEBUG("0x%08lx ", (unsigned long)out[y]); -+ if (out[y] != exp256[x + 1][y]) -+ ret = 1; -+ } -+ if (ret) { -+ SYNHW_PRINT("... FAILED comparison\n"); -+ ret = -1; -+ goto ERR; -+ } else { -+ DEBUG("... PASSED\n"); -+ } -+ } ++&ehci2 { ++ status = "okay"; ++}; + -+ //Test RBC channels -+ // enable RBC channels with rate of 2 and urun 1 -+ enable = 1; -+ rate = 2; -+ urun = 1; -+ for (x = 0; x < nist_trng->config.edu_build_cfg0.rbc_channels; -+ x++) { -+ ret = nisttrng_rbc(nist_trng, enable, x, rate, urun); -+ if (ret) -+ goto ERR; ++&ehci3 { ++ status = "disabled"; ++}; + -+ tmp = pdu_io_read32(nist_trng->base + -+ NIST_TRNG_EDU_RBC_CTRL); ++&pcie2 { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts 2026-09-09 15:51:27.103504249 +0000 +@@ -0,0 +1,1306 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ switch (x) { -+ case 0: -+ if (rate != NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH0_RATE) || -+ urun != NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH0_URUN_BLANK)) { -+ goto ERR; -+ } -+ break; -+ case 1: -+ if (rate != NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH1_RATE) || -+ urun != NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH1_URUN_BLANK)) { -+ goto ERR; -+ } -+ break; -+ case 2: -+ if (rate != NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH2_RATE) || -+ urun != NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH2_URUN_BLANK)) { -+ goto ERR; -+ } -+ break; -+ default: -+ DEBUG("Incorrect rbc_num = %d\n", x); -+ goto ERR; -+ } -+ } -+ DEBUG("RBC test passed\n"); -+ } ++/dts-v1/; ++#include "aspeed-g7.dtsi" ++#include ++#include ++#include + -+ //IF RNCis not disable, disable it -+ if (pdu_io_read32(nist_trng->base + NIST_TRNG_EDU_RNC_CTRL) != -+ NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE) { -+ nisttrng_rnc(nist_trng, -+ NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE); -+ tmp = NIST_TRNG_REG_ISTAT_DONE; -+ //always clear the busy bit after disabling RNC -+ pdu_io_write32(nist_trng->base + NIST_TRNG_REG_ISTAT, tmp); -+ } ++#define DUAL_NODE 0 // 1: DUAL_NODE, 0: SINGLE_NODE ++#define PCIE0_EP 1 // 1: EP, 0: RC ++#define PCIE1_EP 1 // 1: EP, 0: RC ++#define PCIE2_RC 1 // 1: RC, 0: SGMII + -+ /* back to the noise mode */ -+ ret = nisttrng_set_nonce_mode(nist_trng, 0); -+ if (ret) -+ goto ERR; ++/ { ++ model = "AST2700A1 EVB"; ++ compatible = "aspeed,ast2700-evb", "aspeed,ast2700"; + -+ ret = nisttrng_zeroize(nist_trng); -+ if (ret) -+ goto ERR; -+ERR: -+ return ret; -+} ++ chosen { ++ stdout-path = "serial12:115200n8"; ++ }; + -+static int nisttrng_driver_probe(struct platform_device *pdev) -+{ -+ struct synopsys_nisttrng_driver *data; -+ struct hwrng *hwrng_driver_info = 0; -+ struct resource *cfg, *irq; -+ u32 *base_addr; -+ int ret; ++ memory@400000000 { ++ device_type = "memory"; ++ reg = <0x4 0x00000000 0x0 0x40000000>; ++ }; + -+ // version -+ SYNHW_PRINT("DWC_TRNG_DriverSDK_%s\n", TRNG_VERSION); ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; + -+ cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ #include "ast2700-reserved-mem.dtsi" + -+ if (!cfg || !irq) { -+ SYNHW_PRINT("no memory or IRQ resource\n"); -+ return -ENOMEM; -+ } ++ video_engine_memory0: video0 { ++ size = <0x0 0x02000000>; ++ alignment = <0x0 0x00010000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; + -+ DEBUG("=================================================================\n"); -+ DEBUG("nisttrng_probe: Device at %08lx(%08lx) of size %lu bytes\n", -+ (unsigned long)cfg->start, (unsigned long)cfg->end, -+ (unsigned long)resource_size(cfg)); ++ video_engine_memory1: video1 { ++ size = <0x0 0x02000000>; ++ alignment = <0x0 0x00010000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; + -+ data = devm_kzalloc(&pdev->dev, sizeof(struct synopsys_nisttrng_driver), -+ GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; ++ rvas_memory0: rvas0{ ++ size = <0x0 0x04000000>; ++ alignment = <0x0 0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; + -+ platform_set_drvdata(pdev, data); ++ rvas_memory1: rvas1{ ++ size = <0x0 0x04000000>; ++ alignment = <0x0 0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; + -+ base_addr = pdu_linux_map_regs(&pdev->dev, cfg); -+ if (IS_ERR(base_addr)) { -+ dev_err(&pdev->dev, "unable to remap io mem\n"); -+ return PTR_ERR(base_addr); -+ } ++#if 0 ++ gfx_memory: framebuffer { ++ size = <0x0 0x01000000>; ++ alignment = <0x0 0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++#endif + -+ ret = nisttrng_init(&data->nisttrng, (u32 *)base_addr); -+ if (ret) { -+ SYNHW_PRINT("NIST_TRNG init failed (%d)\n", ret); -+ devm_kfree(&pdev->dev, data); -+ return ret; -+ } ++ espi0_mcyc_memory: mcyc0 { ++ size = <0x0 0x01000000>; ++ alignment = <0x0 0x00010000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ }; + -+ /* if max_reads is not 0, change the max_req_per_seed according to max_reads */ -+ if (max_reads) { -+ ret = nisttrng_set_reminder_max_req_per_seed(&data->nisttrng, max_reads); -+ if (ret) { -+ SYNHW_PRINT("NIST_TRNG maximum request-per-seed setup failed (%d)\n", -+ ret); -+ devm_kfree(&pdev->dev, data); -+ return ret; -+ } -+ } ++ fan0: pwm-fan0 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 0 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ // issue quick self test -+ ret = nisttrng_self_test(&data->nisttrng); -+ if (ret) { -+ devm_kfree(&pdev->dev, data); -+ return -ENOMEM; -+ } ++ fan1: pwm-fan1 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 1 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ // ready the device for use -+ ret = nisttrng_instantiate(&data->nisttrng, -+ data->nisttrng.config.features.drbg_arch ? 256 : 128, 1, NULL); -+ if (ret) { -+ SYNHW_PRINT("NIST_TRNG instantiate failed (%d)\n", ret); -+ devm_kfree(&pdev->dev, data); -+ return -ENOMEM; -+ } ++ fan2: pwm-fan2 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 2 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ // at this point the device should be ready for a call to gen_random -+ hwrng_driver_info = -+ devm_kzalloc(&pdev->dev, sizeof(struct hwrng), GFP_KERNEL); -+ if (!hwrng_driver_info) { -+ devm_kfree(&pdev->dev, data); -+ return -ENOMEM; -+ } ++ fan3: pwm-fan3 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 3 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ hwrng_driver_info->name = devm_kzalloc(&pdev->dev, -+ sizeof(SYNOPSYS_HWRNG_DRIVER_NAME) + 1, GFP_KERNEL); -+ if (!hwrng_driver_info->name) { -+ devm_kfree(&pdev->dev, data); -+ devm_kfree(&pdev->dev, hwrng_driver_info); -+ return -ENOMEM; -+ } ++ fan4: pwm-fan4 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 4 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ memset((void *)hwrng_driver_info->name, 0, -+ sizeof(SYNOPSYS_HWRNG_DRIVER_NAME) + 1); -+ strscpy((char *)hwrng_driver_info->name, SYNOPSYS_HWRNG_DRIVER_NAME, -+ sizeof(SYNOPSYS_HWRNG_DRIVER_NAME)); ++ fan5: pwm-fan5 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 5 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ hwrng_driver_info->read = &nisttrng_hwrng_driver_read; -+ hwrng_driver_info->data_present = 0; -+ hwrng_driver_info->priv = (unsigned long)pdev; -+ hwrng_driver_info->quality = 1024; ++ fan6: pwm-fan6 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 6 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ data->hwrng_drv = hwrng_driver_info; -+ ret = hwrng_register(hwrng_driver_info); ++ fan7: pwm-fan7 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 7 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ if (ret) { -+ SYNHW_PRINT("unable to load HWRNG driver (error %d)\n", ret); -+ devm_kfree(&pdev->dev, (void *)hwrng_driver_info->name); -+ devm_kfree(&pdev->dev, hwrng_driver_info); -+ devm_kfree(&pdev->dev, data); -+ return ret; -+ } ++ fan8: pwm-fan8 { ++ compatible = "pwm-fan"; ++ pwms = <&pwm_tach 8 40000 0>; /* Target freq:25 kHz */ ++ cooling-min-state = <0>; ++ cooling-max-state = <3>; ++ #cooling-cells = <2>; ++ cooling-levels = <0 15 128 255>; ++ }; + -+ ret = sysfs_create_group(&pdev->dev.kobj, &nisttrng_attr_group); -+ if (ret < 0) { -+ SYNHW_PRINT("unable to initialize sysfs group (error %d)\n", -+ ret); -+ hwrng_unregister(hwrng_driver_info); -+ devm_kfree(&pdev->dev, (void *)hwrng_driver_info->name); -+ devm_kfree(&pdev->dev, hwrng_driver_info); -+ devm_kfree(&pdev->dev, data); -+ return ret; -+ } -+ SYNHW_PRINT("SYN NIST_TRNG registering HW_RANDOM\n"); -+ return 0; -+} ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ status = "okay"; ++ io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, ++ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, ++ <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>, ++ <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>; ++ }; ++}; + -+static void nisttrng_driver_remove(struct platform_device *pdev) -+{ -+ struct synopsys_nisttrng_driver *data = platform_get_drvdata(pdev); -+ struct hwrng *hwrng_driver_info = (struct hwrng *)data->hwrng_drv; ++&pwm_tach { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default ++ &pinctrl_pwm2_default &pinctrl_pwm3_default ++ &pinctrl_pwm4_default &pinctrl_pwm5_default ++ &pinctrl_pwm6_default &pinctrl_pwm7_default ++ &pinctrl_pwm8_default ++ &pinctrl_tach0_default &pinctrl_tach1_default ++ &pinctrl_tach2_default &pinctrl_tach3_default ++ &pinctrl_tach4_default &pinctrl_tach5_default ++ &pinctrl_tach6_default &pinctrl_tach7_default ++ &pinctrl_tach8_default &pinctrl_tach9_default ++ &pinctrl_tach10_default &pinctrl_tach11_default ++ &pinctrl_tach12_default &pinctrl_tach13_default ++ &pinctrl_tach14_default &pinctrl_tach15_default>; ++ fan-0 { ++ tach-ch = /bits/ 8 <0x0>; ++ }; ++ fan-1 { ++ tach-ch = /bits/ 8 <0x1>; ++ }; ++ fan-2 { ++ tach-ch = /bits/ 8 <0x2>; ++ }; ++ fan-3 { ++ tach-ch = /bits/ 8 <0x3>; ++ }; ++ fan-4 { ++ tach-ch = /bits/ 8 <0x4>; ++ }; ++ fan-5 { ++ tach-ch = /bits/ 8 <0x5>; ++ }; ++ fan-6 { ++ tach-ch = /bits/ 8 <0x6>; ++ }; ++ fan-7 { ++ tach-ch = /bits/ 8 <0x7>; ++ }; ++ fan-8 { ++ tach-ch = /bits/ 8 <0x8>; ++ }; ++ fan-9 { ++ tach-ch = /bits/ 8 <0x9>; ++ }; ++ fan-10 { ++ tach-ch = /bits/ 8 <0xA>; ++ }; ++ fan-11 { ++ tach-ch = /bits/ 8 <0xB>; ++ }; ++ fan-12 { ++ tach-ch = /bits/ 8 <0xC>; ++ }; ++ fan-13 { ++ tach-ch = /bits/ 8 <0xD>; ++ }; ++ fan-14 { ++ tach-ch = /bits/ 8 <0xE>; ++ }; ++ fan-15 { ++ tach-ch = /bits/ 8 <0xF>; ++ }; ++}; + -+ SYNHW_PRINT("SYN NIST_TRNG unregistering from HW_RANDOM\n"); -+ hwrng_unregister(hwrng_driver_info); -+ sysfs_remove_group(&pdev->dev.kobj, &nisttrng_attr_group); -+ devm_kfree(&pdev->dev, (void *)hwrng_driver_info->name); -+ devm_kfree(&pdev->dev, hwrng_driver_info); -+ devm_kfree(&pdev->dev, data); -+} ++&edac { ++ status = "okay"; ++}; + -+static struct platform_driver s_nisttrng_platform_driver_info = { -+ .probe = nisttrng_driver_probe, -+ .remove = nisttrng_driver_remove, -+ .driver = { -+ .name = "nist_trng", -+ .owner = THIS_MODULE, -+ }, ++&mctp0 { ++ status = "okay"; ++ memory-region = <&mctp0_reserved>; +}; + -+static int __init nisttrng_platform_driver_start(void) -+{ -+ return platform_driver_register(&s_nisttrng_platform_driver_info); -+} ++&mctp1 { ++ status = "okay"; ++ memory-region = <&mctp1_reserved>; ++}; + -+static void __exit nisttrng_platform_driver_end(void) -+{ -+ platform_driver_unregister(&s_nisttrng_platform_driver_info); -+} ++&mctp2 { ++ status = "okay"; ++ memory-region = <&mctp2_reserved>; ++}; + -+module_init(nisttrng_platform_driver_start); -+module_exit(nisttrng_platform_driver_end); ++&sgpiom0 { ++ status = "okay"; ++}; + -+module_param(max_reads, ulong, 0); -+MODULE_PARM_DESC(max_reads, "Max # of reads between reseeds (default is 128)"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Synopsys, Inc."); -diff --git a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c ---- a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c 2025-12-23 10:16:19.525059469 +0000 -@@ -0,0 +1,956 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++&sgpiom1 { ++ status = "okay"; ++}; + -+#include "nisttrng_hw.h" -+#include "nisttrng.h" ++&jtag1 { ++ status = "okay"; ++}; + -+/* Initialize the NIST_TRNG state structure */ -+int nisttrng_init(struct nist_trng_state *state, u32 *base) -+{ -+ int err; -+ u32 tmp; ++&adc0 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; + -+ DEBUG(">> %s: initialize the NIST_TRNG\n", __func__); ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default ++ &pinctrl_adc2_default &pinctrl_adc3_default ++ &pinctrl_adc4_default &pinctrl_adc5_default ++ &pinctrl_adc6_default &pinctrl_adc7_default>; ++}; + -+ memset(state, 0, sizeof(*state)); ++&adc1 { ++ aspeed,int-vref-microvolt = <2500000>; ++ status = "okay"; + -+ state->base = base; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default ++ &pinctrl_adc10_default &pinctrl_adc11_default ++ &pinctrl_adc12_default &pinctrl_adc13_default ++ &pinctrl_adc14_default &pinctrl_adc15_default>; ++}; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++&pinctrl0 { ++ pinctrl_emmcclk_driving: emmcclk-driving { ++ pins = "AC14"; ++ drive-strength = <2>; ++ }; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; -+ -+ /* hardware features*/ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_FEATURES); -+ -+ state->config.features.drbg_arch = NIST_TRNG_REG_FEATURES_AES_256(tmp); -+ state->config.features.extra_ps_present = -+ NIST_TRNG_REG_FEATURES_EXTRA_PS_PRESENT(tmp); -+ state->config.features.secure_rst_state = -+ NIST_TRNG_REG_FEATURES_SECURE_RST_STATE(tmp); -+ state->config.features.diag_level_basic_trng = -+ NIST_TRNG_REG_FEATURES_DIAG_LEVEL_BASIC_TRNG(tmp); -+ state->config.features.diag_level_stat_hlt = -+ NIST_TRNG_REG_FEATURES_DIAG_LEVEL_ST_HLT(tmp); -+ state->config.features.diag_level_ns = -+ NIST_TRNG_REG_FEATURES_DIAG_LEVEL_NS(tmp); -+ -+ /* corekit */ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_COREKIT_REL); -+ state->config.corekit_rel.ext_enum = NIST_TRNG_REG_EXT_ENUM(tmp); -+ state->config.corekit_rel.ext_ver = NIST_TRNG_REG_EXT_VER(tmp); -+ state->config.corekit_rel.rel_num = NIST_TRNG_REG_REL_NUM(tmp); -+ -+ /* clear registers */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_ALARM, 0xFFFFFFFF); -+ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, 0xFFFFFFFF); -+ -+ /* setup the NIST_TRNG in secure mode, self seeding mode, with prediction resistance, maximum possible security strength */ -+ /* SMODE */ -+ tmp = 0; -+ tmp = NIST_TRNG_REG_SMODE_SET_SECURE_EN(tmp, 1); -+ tmp = NIST_TRNG_REG_SMODE_SET_NONCE(tmp, 0); -+ tmp = NIST_TRNG_REG_SMODE_SET_MAX_REJECTS(tmp, -+ NIST_TRNG_DFLT_MAX_REJECTS); -+ pdu_io_write32(state->base + NIST_TRNG_REG_SMODE, tmp); -+ state->status.secure_mode = 1; -+ state->status.nonce_mode = 0; -+ /* MODE */ -+ tmp = 0; -+ if (state->config.features.drbg_arch == AES256) { -+ tmp = NIST_TRNG_REG_MODE_SET_SEC_ALG(tmp, 1); -+ state->status.sec_strength = SEC_STRNT_AES256; -+ -+ } else if (state->config.features.drbg_arch == AES128) { -+ tmp = NIST_TRNG_REG_MODE_SET_SEC_ALG(tmp, 0); -+ state->status.sec_strength = SEC_STRNT_AES128; ++ pinctrl_emmccmd_driving: emmccmd-driving { ++ pins = "AE15"; ++ drive-strength = <1>; ++ }; ++ pinctrl_emmc4bit_driving: emmcdat-driving { ++ pins = "AD14", "AE14", "AF14", "AB13"; ++ drive-strength = <1>; ++ }; + -+ } else { -+ SYNHW_PRINT("Invalid DRBG architecture"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ tmp = NIST_TRNG_REG_MODE_SET_PRED_RESIST(tmp, 1); -+ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, 0); -+ state->status.pred_resist = 1; -+ /* rest of the status */ -+ state->status.alarm_code = 0; -+ state->status.pad_ps_addin = 0; -+ -+ /* reminders - set the counters to the standard's maximum values. An API is be provided to change those on demand.*/ -+ nisttrng_set_reminder_max_bits_per_req(state, -+ NIST_DFLT_MAX_BITS_PER_REQ); -+ nisttrng_set_reminder_max_req_per_seed(state, -+ NIST_DFLT_MAX_REQ_PER_SEED); -+ -+ /* display features */ -+ SYNHW_PRINT("NIST_TRNG: Hardware rel_num=0x%x, ext_ver=0x%x, ext_enum=0x%x\n", -+ state->config.corekit_rel.rel_num, -+ state->config.corekit_rel.ext_ver, -+ state->config.corekit_rel.ext_enum); -+ switch (state->config.features.drbg_arch) { -+ case AES128: -+ DEBUG("NIST_TRNG: DRBG Architecture=128-bit AES, Extra Personalization Existence=%u\n", -+ state->config.features.extra_ps_present); -+ break; -+ case AES256: -+ DEBUG("NIST_TRNG: DRBG Architecture=256-bit AES, Extra Personalization Existence=%u\n", -+ state->config.features.extra_ps_present); -+ break; -+ default: -+ SYNHW_PRINT("Invalid DRBG architecture"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ DEBUG("initialization is done, going for a zeroize\n"); -+ -+ // BUILD_CFG0 -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_BUILD_CFG0); -+ state->config.build_cfg0.core_type = NIST_TRNG_REG_CFG0_CORE_TYPE(tmp); -+ state->config.build_cfg0.bg8 = NIST_TRNG_REG_CFG0_BG8(tmp); -+ state->config.build_cfg0.cdc_synch_depth = -+ NIST_TRNG_REG_CFG0_CDC_SYNCH_DEPTH(tmp); -+ state->config.build_cfg0.background_noise = -+ NIST_TRNG_REG_CFG0_BACGROUND_NOISE(tmp); -+ state->config.build_cfg0.edu_present = -+ NIST_TRNG_REG_CFG0_EDU_PRESENT(tmp); -+ state->config.build_cfg0.aes_datapath = -+ NIST_TRNG_REG_CFG0_AES_DATAPATH(tmp); -+ state->config.build_cfg0.aes_max_key_size = -+ NIST_TRNG_REG_CFG0_AES_MAX_KEY_SIZE(tmp); -+ state->config.build_cfg0.personilzation_str = -+ NIST_TRNG_REG_CFG0_PERSONILIZATION_STR(tmp); -+ DEBUG("NIST_TRNG: BUILD_CFG0 core_type=%u, bg8=%u, cdc_synch_depth=%u, background_noise=%u\n", -+ state->config.build_cfg0.core_type, state->config.build_cfg0.bg8, -+ state->config.build_cfg0.cdc_synch_depth, -+ state->config.build_cfg0.background_noise); -+ DEBUG("edu_present=%u, aes_datapath=%u, aes_max_key_size=%u, personilzation_str=%u\n", -+ state->config.build_cfg0.edu_present, -+ state->config.build_cfg0.aes_datapath, -+ state->config.build_cfg0.aes_max_key_size, -+ state->config.build_cfg0.personilzation_str); -+ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_BUILD_CFG1); -+ DEBUG("NIST_TRNG: NIST_TRNG_REG_BUILD_CFG1=0x%x\n", tmp); -+ state->config.build_cfg1.num_raw_noise_blks = -+ NIST_TRNG_REG_CFG1_NUM_RAW_NOISE_BLKS(tmp); -+ state->config.build_cfg1.sticky_startup = -+ NIST_TRNG_REG_CFG1_STICKY_STARTUP(tmp); -+ state->config.build_cfg1.auto_correlation_test = -+ NIST_TRNG_REG_CFG1_AUTO_CORRELATION_TEST(tmp); -+ state->config.build_cfg1.mono_bit_test = -+ NIST_TRNG_REG_CFG1_MONO_BIT_TEST(tmp); -+ state->config.build_cfg1.run_test = NIST_TRNG_REG_CFG1_RUN_TEST(tmp); -+ state->config.build_cfg1.poker_test = -+ NIST_TRNG_REG_CFG1_POKER_TEST(tmp); -+ state->config.build_cfg1.raw_ht_adap_test = -+ NIST_TRNG_REG_CFG1_RAW_HT_ADAP_TEST(tmp); -+ state->config.build_cfg1.raw_ht_rep_test = -+ NIST_TRNG_REG_CFG1_RAW_HT_REP_TEST(tmp); -+ state->config.build_cfg1.ent_src_rep_smpl_size = -+ NIST_TRNG_REG_CFG1_ENT_SRC_REP_SMPL_SIZE(tmp); -+ state->config.build_cfg1.ent_src_rep_test = -+ NIST_TRNG_REG_CFG1_ENT_SRC_REP_TEST(tmp); -+ state->config.build_cfg1.ent_src_rep_min_entropy = -+ NIST_TRNG_REG_CFG1_ENT_SRC_REP_MIN_ENTROPY(tmp); -+ DEBUG("NIST_TRNG: BUILD_CFG1 num_raw_noise_blks=%u, sticky_startup=%u, auto_correlation_test=%u\n", -+ state->config.build_cfg1.num_raw_noise_blks, -+ state->config.build_cfg1.sticky_startup, -+ state->config.build_cfg1.auto_correlation_test); -+ DEBUG("mono_bit_test=%u, run_test=%u, poker_test=%u, raw_ht_adap_test=%u\n", -+ state->config.build_cfg1.mono_bit_test, -+ state->config.build_cfg1.run_test, -+ state->config.build_cfg1.poker_test, -+ state->config.build_cfg1.raw_ht_adap_test); -+ DEBUG("raw_ht_rep_test=%u, ent_src_rep_smpl_size=%u, ent_src_rep_test=%u, ent_src_rep_min_entropy=%u\n", -+ state->config.build_cfg1.raw_ht_rep_test, -+ state->config.build_cfg1.ent_src_rep_smpl_size, -+ state->config.build_cfg1.ent_src_rep_test, -+ state->config.build_cfg1.ent_src_rep_min_entropy); -+ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_BUILD_CFG0); -+ state->config.edu_build_cfg0.rbc2_rate_width = -+ NIST_TRNG_REG_EDU_CFG0_RBC2_RATE_WIDTH(tmp); -+ state->config.edu_build_cfg0.rbc1_rate_width = -+ NIST_TRNG_REG_EDU_CFG0_RBC1_RATE_WIDTH(tmp); -+ state->config.edu_build_cfg0.rbc0_rate_width = -+ NIST_TRNG_REG_EDU_CFG0_RBC0_RATE_WIDTH(tmp); -+ state->config.edu_build_cfg0.public_vtrng_channels = -+ NIST_TRNG_REG_EDU_CFG0_PUBLIC_VTRNG_CHANNELS(tmp); -+ state->config.edu_build_cfg0.esm_channel = -+ NIST_TRNG_REG_EDU_CFG0_ESM_CHANNEL(tmp); -+ state->config.edu_build_cfg0.rbc_channels = -+ NIST_TRNG_REG_EDU_CFG0_RBC_CHANNELS(tmp); -+ state->config.edu_build_cfg0.fifo_depth = -+ NIST_TRNG_REG_EDU_CFG0_FIFO_DEPTH(tmp); -+ DEBUG("NIST_TRNG: EDU_BUILD_CFG0 rbc2_rate_width=%u, rbc1_rate_width=%u, rbc0_rate_width=%u\n", -+ state->config.edu_build_cfg0.rbc2_rate_width, -+ state->config.edu_build_cfg0.rbc1_rate_width, -+ state->config.edu_build_cfg0.rbc0_rate_width); -+ DEBUG("public_vtrng_channels=%u, esm_channel=%u, rbc_channels=%u, fifo_depth=%u\n", -+ state->config.edu_build_cfg0.public_vtrng_channels, -+ state->config.edu_build_cfg0.esm_channel, -+ state->config.edu_build_cfg0.rbc_channels, -+ state->config.edu_build_cfg0.fifo_depth); -+ -+ state->status.edu_vstat.seed_enum = -+ NIST_TRNG_REG_EDU_VSTAT_SEED_ENUM(tmp); -+ state->status.edu_vstat.rnc_enabled = -+ NIST_TRNG_REG_EDU_VSTAT_RNC_ENABLED(tmp); -+ -+ err = nisttrng_zeroize(state); -+ if (err) -+ goto ERR; ++ pinctrl_emmc8bit_driving: emmcdat-driving { ++ pins = "AD14", "AE14", "AF14", "AB13", "AF13", "AC13", "AD13", "AE13"; ++ drive-strength = <1>; ++ }; ++}; + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_INITIALIZE; -+ERR: -+ DEBUG("--- %s Return, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_init */ -+EXPORT_SYMBOL(nisttrng_init); ++&pinctrl1 { ++ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { ++ pins = "U25"; ++ power-source = <1800>; ++ }; + -+/* Instantiate the DRBG state */ -+int nisttrng_instantiate(struct nist_trng_state *state, int req_sec_strength, -+ int pred_resist, void *personal_str) -+{ -+ int err; -+ u32 tmp; -+ u32 zero_ps[12] = { 0 }; -+ int i = 0; ++ pinctrl_i3c0_driving: i3c0-driving { ++ pins = "U25", "U26"; ++ drive-strength = <2>; ++ }; + -+ DEBUG(">> %s: security strength = %u, pred_resist = %u, personilization string existence = %u\n", -+ __func__, req_sec_strength, pred_resist, (personal_str) ? 1 : 0); ++ pinctrl_i3c1_driving: i3c1-driving { ++ pins = "Y26", "AA24"; ++ drive-strength = <2>; ++ }; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ pinctrl_i3c2_driving: i3c2-driving { ++ pins = "R25", "AA26"; ++ drive-strength = <2>; ++ }; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++ pinctrl_i3c3_driving: i3c3-driving { ++ pins = "R26", "Y25"; ++ drive-strength = <2>; ++ }; + -+ /* If DRBG is already instantiated or if current state does not allow an instantiate, return error */ -+ if (DRBG_INSTANTIATED(state->status.current_state)) { -+ DEBUG("Initial check: DRBG state is already instantiated\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ if (state->status.current_state != NIST_TRNG_STATE_INITIALIZE && -+ state->status.current_state != NIST_TRNG_STATE_UNINSTANTIATE) { -+ DEBUG("Cannot instantiate in the current state (%u)\n", -+ state->status.current_state); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ pinctrl_i3c12_15_hv_voltage: i3chv-voltage { ++ pins = "W25"; ++ power-source = <1800>; ++ }; + -+ /* if hardware is not configured to accept extra personalization string, but personal_str is not NULL, return error */ -+ if (!state->config.features.extra_ps_present && personal_str) { -+ DEBUG("HW config does not allow extra PS\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ pinctrl_i3c12_driving: i3c12-driving { ++ pins = "W25", "Y23"; ++ drive-strength = <2>; ++ }; + -+ /* Validate and set the security strength */ -+ err = nisttrng_set_sec_strength(state, req_sec_strength); -+ if (err) -+ goto ERR; ++ pinctrl_i3c13_driving: i3c13-driving { ++ pins = "Y24", "W21"; ++ drive-strength = <2>; ++ }; + -+ /* get entropy - noise seeding. If the mode is nonce, get_entropy must be called by the user prior to the instantiate function */ -+ DEBUG("Seeding mode is: %s\n", -+ state->status.nonce_mode ? "Nonce" : "Noise"); -+ if (!state->status.nonce_mode) { /* noise seeding */ -+ err = nisttrng_get_entropy_input(state, NULL, 0); -+ if (err) -+ goto ERR; -+ } ++ pinctrl_i3c14_driving: i3c14-driving { ++ pins = "AA23", "AC22"; ++ drive-strength = <2>; ++ }; + -+ /* load the personilization string if hardware is configured to accept it */ -+ if (state->config.features.extra_ps_present) { -+ /* if HW is configured to accept personilizatoin string, it will use whatever is in the NPA_DATAx. So, if the string is NULL, just load 0. */ -+ if (!personal_str) -+ personal_str = &zero_ps[0]; ++ pinctrl_i3c15_driving: i3c15-driving { ++ pins = "AB22", "Y21"; ++ drive-strength = <2>; ++ }; + -+ err = nisttrng_load_ps_addin(state, personal_str); -+ if (err) -+ goto ERR; -+ } ++ pinctrl_rgmii0_driving: rgmii0-driving { ++ pins = "C20", "C19", "A8", "R14", "A7", "P14", ++ "D20", "A6", "B6", "N14", "B7", "B8"; ++ drive-strength = <1>; ++ }; + -+ /* initiate the Create_State command and wait on done */ -+ DEBUG("Create the DRBG state\n"); ++ pinctrl_rgmii1_driving: rgmii1-driving { ++ pins = "D19", "C19", "D15", "B12", "B10", "P13", ++ "C18", "C6", "C7", "D7", "N13", "C8"; ++ drive-strength = <1>; ++ }; ++}; + -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_CREATE_STATE); -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; ++&gpio1 { ++ pinctrl-0 = <&pinctrl_i3c0_3_hv_voltage &pinctrl_i3c12_15_hv_voltage ++ &pinctrl_i3c0_driving &pinctrl_i3c1_driving ++ &pinctrl_i3c2_driving &pinctrl_i3c3_driving ++ &pinctrl_i3c12_driving &pinctrl_i3c13_driving ++ &pinctrl_i3c14_driving &pinctrl_i3c15_driving>; ++ pinctrl-names = "default"; ++}; + -+ /* check STAT register to make sure DRBG is instantiated */ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); -+ if (!NIST_TRNG_REG_STAT_GET_DRBG_STATE(tmp)) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&i3c0 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06010000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* reset reminder and alarms counters */ -+ nisttrng_reset_counters(state); ++&i3c1 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ //if EDU is available enable RNC and disable prediction resistance , disable all RBC,s -+ //state->config.build_cfg0.edu_present = 0; -+ if (state->config.build_cfg0.edu_present) { -+ //disable prediction resistance -+ err = nisttrng_set_pred_resist(state, 0); -+ if (err) -+ goto ERR; ++&i3c2 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06012000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ //enable RNC -+ nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE); -+ // disable all RBC,s -+ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); -+ for (i = 0; i < state->config.edu_build_cfg0.rbc_channels; -+ i++) { -+ err = nisttrng_rbc(state, 0, i, 0, -+ CHX_URUN_BLANK_AFTER_RESET); -+ if (err) -+ goto ERR; -+ } -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); -+ -+ } else { -+ /* set the prediction resistance */ -+ err = nisttrng_set_pred_resist(state, pred_resist); -+ if (err) -+ goto ERR; -+ } ++&i3c3 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_INSTANTIATE; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_instantiate */ -+EXPORT_SYMBOL(nisttrng_instantiate); ++&i3c4 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06014000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+/* Uninstantiate the DRBG state and zeroize */ -+int nisttrng_uninstantiate(struct nist_trng_state *state) -+{ -+ int err; -+ int err_tmp; -+ u32 tmp; ++&i3c5 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ DEBUG(">> %s: uninstantiate the DRBG and zeroize\n", __func__); -+ //printf(" nisttrng_uninstantiate: uninstantiate the DRBG and zeroize\n"); -+ err = CRYPTO_OK; -+ err_tmp = CRYPTO_OK; ++&i3c6 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06016000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ //disable RNC -+ if (state->config.build_cfg0.edu_present) { -+ if (state->status.edu_vstat.rnc_enabled) { -+ DEBUG("%s: disable RNC\n", __func__); -+ nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE); -+ //always clear the busy bit after disabling RNC -+ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, tmp); -+ } -+ } ++&i3c7 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ /* if DRBG is instantiated, return CRYPTO_NOT_INSTANTIATED, but still do the zeroize */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) -+ err_tmp = CRYPTO_NOT_INSTANTIATED; ++&i3c8 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x06018000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ /* zeroize */ -+ err = nisttrng_zeroize(state); -+ if (err) -+ goto ERR; ++&i3c9 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ if (err == CRYPTO_OK && err_tmp == CRYPTO_NOT_INSTANTIATED) -+ err = CRYPTO_NOT_INSTANTIATED; ++&i3c10 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601A000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ state->status.current_state = NIST_TRNG_STATE_UNINSTANTIATE; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_uninstantiate */ -+EXPORT_SYMBOL(nisttrng_uninstantiate); ++&i3c11 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+/* enable/disable specific rbc -+ * rbc_num = rbc channel num -+ * urun_blnk = underrun blanking duration for rbc channel -+ * rate = sets rate of serial entropy output for rbc channel -+ */ -+int nisttrng_rbc(struct nist_trng_state *state, int enable, int rbc_num, int rate, -+ int urun_blnk) -+{ -+ int err = 0; -+ u32 tmp_rbc = 0; ++&i3c12 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601C000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ tmp_rbc = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); ++&i3c13 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ if (enable) { -+ if (rate > 15) { -+ DEBUG("Incorrect rate = %d\n", rate); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ if (urun_blnk > 3) { -+ DEBUG("Incorrect urun_blnk = %d\n", urun_blnk); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ } else { //disable -+ rate = NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE_AFTER_RESET; -+ urun_blnk = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK_AFTER_RESET; -+ } ++&i3c14 { ++ initial-role = "target"; ++ pid = <0x000007ec 0x0601E000>; ++ dcr = /bits/ 8 <0xcc>; ++ status = "okay"; ++}; + -+ switch (rbc_num) { -+ case 0: -+ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(rate, tmp_rbc, _NIST_TRNG_EDU_RBC_CTRL_CH0_RATE); -+ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(urun_blnk, tmp_rbc, -+ _NIST_TRNG_EDU_RBC_CTRL_CH0_URUN_BLANK); ++&i3c15 { ++ initial-role = "primary"; ++ status = "okay"; ++}; + -+ break; -+ case 1: -+ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(rate, tmp_rbc, _NIST_TRNG_EDU_RBC_CTRL_CH1_RATE); -+ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(urun_blnk, tmp_rbc, -+ _NIST_TRNG_EDU_RBC_CTRL_CH1_URUN_BLANK); ++&uart12 { ++ status = "okay"; ++}; + -+ break; -+ case 2: -+ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(rate, tmp_rbc, _NIST_TRNG_EDU_RBC_CTRL_CH2_RATE); -+ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(urun_blnk, tmp_rbc, -+ _NIST_TRNG_EDU_RBC_CTRL_CH2_URUN_BLANK); -+ break; -+ default: -+ DEBUG("Incorrect rbc_num = %d\n", rbc_num); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++#if 0 ++&vuart0 { ++ virtual; ++ port = <0x3f8>; ++ sirq = <4>; ++ sirq-polarity = <0>; ++ status = "okay"; ++}; ++#endif + -+ pdu_io_write32(state->base + NIST_TRNG_EDU_RBC_CTRL, tmp_rbc); ++&fmc { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_fwspi_quad_default>; ++ pinctrl-names = "default"; + -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "bmc"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++#include "aspeed-evb-flash-layout-128.dtsi" ++ }; + -+/* Reseed */ -+int nisttrng_reseed(struct nist_trng_state *state, int pred_resist, void *addin_str) -+{ -+ int rnc_flag = 0; -+ int err; ++ flash@1 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "fmc0:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; + -+ DEBUG(">> %s: pred_resist = %u, additional strign existence = %u\n", -+ __func__, pred_resist, (addin_str) ? 1 : 0); ++ flash@2 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "fmc0:2"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; ++}; + -+ if (state->config.build_cfg0.edu_present) { -+ if (state->status.edu_vstat.rnc_enabled) { -+ // disable_rnc -+ err = nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_DISABLE_TO_HOLD); -+ if (err) -+ goto ERR; ++&spi0 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; ++ pinctrl-names = "default"; + -+ rnc_flag = 1; -+ } -+ } ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi0:0"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ flash@1 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "spi0:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++&spi1 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; ++ pinctrl-names = "default"; + -+ /* if the DRBG is not instantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ DEBUG("DRBG is not instantiated\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi1:0"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; + -+ /* if pred_resist is set but, pred_resist that the DRBG is instantiated with is not 1, return error */ -+ err = nisttrng_set_pred_resist(state, pred_resist); -+ if (err) -+ goto ERR; ++ flash@1 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "spi1:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; + -+ /* get entropy - noise seeding. If the mode is nonce, get_entropy must be called by the user prior to the instantiate function */ -+ if (!state->status.nonce_mode) { /* noise seeding */ -+ err = nisttrng_get_entropy_input(state, NULL, 0); -+ if (err) -+ goto ERR; -+ } ++#if 1 ++&spi2 { ++ compatible = "aspeed,ast2700-spi-txrx"; ++ pinctrl-0 = <&pinctrl_spi2_default>; ++ pinctrl-names = "default"; ++ status = "okay"; + -+ /* if addin_str is not NULL, it means that the additionl input is available and has to be loaded */ -+ if (addin_str) { -+ /* set the ADDIN_PRESENT field of the MODE register to 1 */ -+ err = nisttrng_set_addin_present(state, 1); -+ if (err) -+ goto ERR; ++ tpm0: tpmdev@0 { ++ compatible = "tcg,tpm_tis-spi"; ++ spi-max-frequency = <25000000>; ++ reg = <0>; ++ status = "okay"; ++ }; ++}; ++#else ++&spi2 { ++ compatible = "aspeed,ast2700-spi"; ++ pinctrl-0 = <&pinctrl_spi2_default &pinctrl_spi2_cs1_default>; ++ pinctrl-names = "default"; ++ status = "okay"; + -+ /* load the additional input */ -+ err = nisttrng_load_ps_addin(state, addin_str); -+ if (err) -+ goto ERR; ++ flash@0 { ++ status = "okay"; ++ reg = < 0 >; ++ compatible = "jedec,spi-nor"; ++ m25p,fast-read; ++ label = "spi2:0"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; + -+ } else { -+ /* set the ADDIN_PRESENT field of the MODE register to 0 */ -+ err = nisttrng_set_addin_present(state, 0); -+ if (err) -+ goto ERR; -+ } ++ flash@1 { ++ status = "okay"; ++ reg = < 1 >; ++ compatible = "jedec,spi-nor"; ++ m25p,fast-read; ++ label = "spi2:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; ++#endif + -+ /* initiate the reseed and wait on done */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_RENEW_STATE); -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; ++&can0 { ++ status = "okay"; ++}; + -+ /* reset reminder and alarms counters */ -+ nisttrng_reset_counters(state); ++&emmc_controller { ++ status = "okay"; ++ mmc-hs200-1_8v; ++}; + -+ if (rnc_flag) { -+ // rnc_enable -+ err = nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE); -+ if (err) -+ goto ERR; -+ } ++&emmc { ++ status = "okay"; ++#if 1 ++ bus-width = <4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_emmc_default ++ &pinctrl_emmcclk_driving ++ &pinctrl_emmccmd_driving ++ &pinctrl_emmc4bit_driving>; ++#else ++ bus-width = <8>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_emmc_default ++ &pinctrl_emmcg8_default ++ &pinctrl_emmcclk_driving ++ &pinctrl_emmccmd_driving ++ &pinctrl_emmc8bit_driving>; ++#endif + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_RESEED; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_reseed */ -+EXPORT_SYMBOL(nisttrng_reseed); ++ non-removable; ++ max-frequency = <200000000>; ++}; + -+static int nisttrng_vtrng_wait_on_busy(struct nist_trng_state *state, int priv, int vtrng) -+{ -+ u32 tmp, t; ++&ufs_controller { ++ status = "okay"; ++}; + -+ t = NIST_TRNG_RETRY_MAX; ++&ufs { ++ status = "okay"; ++ lanes-per-direction = <2>; ++ ref-clk-freq = <26000000>; ++}; + -+ if (priv) { //private vtrng -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VSTAT); -+ } while (NIST_TRNG_REG_EDU_VSTAT_BUSY(tmp) && --t); ++&chassis { ++ status = "okay"; ++}; + -+ } else { //public vtrng -+ do { -+ tmp = pdu_io_read32(state->base + -+ NIST_TRNG_EDU_VTRNG_VSTAT0 + -+ 8 * vtrng); -+ } while (NIST_TRNG_REG_EDU_VSTAT_BUSY(tmp) && --t); -+ } ++&mdio0 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ if (t) -+ return CRYPTO_OK; ++ ethphy0: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; + -+ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", -+ (unsigned long)tmp); ++&mdio1 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ return CRYPTO_TIMEOUT; -+} /* nisttrng_vtrng_wait_on_busy */ ++ ethphy1: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ /* For DDR5 board */ ++ ti,rx-internal-delay = ; ++ ti,tx-internal-delay = ; ++ }; ++}; + -+int nisttrng_generate_public_vtrng(struct nist_trng_state *state, void *random_bits, -+ unsigned long req_num_bytes, int vtrng) -+{ -+ int err = 0; -+ u32 tmp; -+ unsigned int remained_bytes; -+ unsigned long req_num_blks; -+ int i, j; ++&mac0 { ++ status = "okay"; + -+ DEBUG(">> %s : requested number of bytes = %lu, vtrng num = %u\n", -+ __func__, req_num_bytes, vtrng); -+ -+ /* make sure random_bits is not NULL */ -+ if (!random_bits) { -+ DEBUG("random_bits pointer cannot be NULL\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ if (vtrng > state->config.edu_build_cfg0.public_vtrng_channels) { -+ DEBUG("vtrng channel invalid (%u)\n", vtrng); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ if (state->status.edu_vstat.rnc_enabled == 0) { -+ DEBUG("rnc_disabled\n"); -+ } -+ -+ if (state->status.edu_vstat.seed_enum == 0) { -+ DEBUG("not seed_enum\n"); -+ } -+ -+ /* loop on generate to get the requested number of bits. Each generate gives NIST_TRNG_RAND_BLK_SIZE_BITS bits. */ -+ req_num_blks = ((req_num_bytes * 8) % NIST_TRNG_RAND_BLK_SIZE_BITS) ? -+ (((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS) + 1) : -+ ((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS); -+ -+ for (i = 0; i < req_num_blks; i++) { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VTRNG_VCTRL0 + -+ (vtrng * 8)); -+ tmp = NIST_TRNG_EDU_VTRNG_VCTRL_CMD_SET(tmp, NIST_TRNG_EDU_VTRNG_VCTRL_CMD_GET_RANDOM); -+ pdu_io_write32(state->base + NIST_TRNG_EDU_VTRNG_VCTRL0 + (vtrng * 8), -+ tmp); -+ -+ // check busy -+ err = nisttrng_vtrng_wait_on_busy(state, 0, vtrng); -+ if (err) -+ goto ERR; -+ -+ // check for error -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VTRNG_VISTAT0 + -+ (vtrng * 8)); -+ if (NIST_TRNG_REG_EDU_VSTAT_ANY_RW1(tmp)) { -+ DEBUG("EDU_VSTAT_ANY_RW1 set 0x%x\n", tmp); -+ } -+ -+ // check that all valid -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VTRNG_VSTAT0 + -+ 8 * vtrng); -+ if ((NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD0(tmp) == 0) || -+ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD1(tmp) == 0) || -+ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD2(tmp) == 0) || -+ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD3(tmp) == 0)) { -+ DEBUG("EDU_VSTAT_SLICE_VLD fail 0x%x\n", tmp); -+ } -+ -+ /* read the generated random number block and store */ -+ for (j = 0; j < (NIST_TRNG_RAND_BLK_SIZE_BITS / 32); j++) { -+ tmp = pdu_io_read32(state->base + -+ NIST_TRNG_EDU_VTRNG_VRAND0_0 + -+ (vtrng * 8) + j); -+ /* copy to random_bits byte-by-byte, until req_num_bytes are copied */ -+ remained_bytes = req_num_bytes - -+ (i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4); -+ if (remained_bytes > 4) { -+ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, 4); -+ -+ /* decrement the bits counter and return error if generated more than the maximum*/ -+ state->counters.bits_per_req_left = -+ state->counters.bits_per_req_left - -+ 4 * 8; -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ } else { -+ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, remained_bytes); -+ -+ /* decrement the bits counter and return error if generated more than the maximum*/ -+ state->counters.bits_per_req_left = -+ state->counters.bits_per_req_left - -+ remained_bytes * 8; -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ break; -+ } -+ } -+ } ++ phy-mode = "rgmii-id"; ++ phy-handle = <ðphy0>; + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_GENERATE; -+ERR: -+ if (err) -+ random_bits = NULL; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; ++}; + -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} ++&mac1 { ++ status = "okay"; + -+static int nisttrng_generate_private_vtrng(struct nist_trng_state *state, void *random_bits, -+ unsigned long req_num_bytes) -+{ -+ int err; -+ u32 tmp; -+ unsigned int remained_bytes; -+ unsigned long req_num_blks; -+ int i, j; ++ phy-mode = "rgmii-id"; ++ phy-handle = <ðphy1>; + -+ DEBUG(">> %s : requested number of bytes = %lu ", -+ __func__, req_num_bytes); -+ -+ /* requested number of bits has to be less that the programmed maximum */ -+ if ((req_num_bytes * 8) > state->counters.max_bits_per_req) { -+ SYNHW_PRINT("requested number of bits (%lu) is larger than the set maximum (%lu)\n", -+ (req_num_bytes * 8), state->counters.max_bits_per_req); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ /* make sure random_bits is not NULL */ -+ if (!random_bits) { -+ SYNHW_PRINT("random_bits pointer cannot be NULL\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ if (state->status.edu_vstat.rnc_enabled == 0) { -+ DEBUG("rnc_disabled\n"); -+ } -+ -+ if (state->status.edu_vstat.seed_enum == 0) { -+ DEBUG("not seed_enum\n"); -+ } -+ -+ /* loop on generate to get the requested number of bits. Each generate gives NIST_TRNG_RAND_BLK_SIZE_BITS bits. */ -+ req_num_blks = ((req_num_bytes * 8) % NIST_TRNG_RAND_BLK_SIZE_BITS) ? -+ (((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS) + 1) : -+ ((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS); -+ -+ for (i = 0; i < req_num_blks; i++) { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VCTRL); -+ tmp = NIST_TRNG_EDU_VTRNG_VCTRL_CMD_SET(tmp, NIST_TRNG_EDU_VTRNG_VCTRL_CMD_GET_RANDOM); -+ pdu_io_write32(state->base + NIST_TRNG_EDU_VCTRL, tmp); -+ -+ // check busy -+ err = nisttrng_vtrng_wait_on_busy(state, 1, 0); -+ if (err) -+ goto ERR; -+ -+ // check for error -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VISTAT); -+ if (NIST_TRNG_REG_EDU_VSTAT_ANY_RW1(tmp)) { -+ DEBUG("EDU_VSTAT_ANY_RW1 set 0x%x\n", tmp); -+ } -+ -+ //check that all valid -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VSTAT); -+ if ((NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD0(tmp) == 0) || -+ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD1(tmp) == 0) || -+ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD2(tmp) == 0) || -+ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD3(tmp) == 0)) { -+ DEBUG("EDU_VSTAT_SLICE_VLD fail 0x%x\n", tmp); -+ } -+ -+ /* read the generated random number block and store */ -+ for (j = 0; j < (NIST_TRNG_RAND_BLK_SIZE_BITS / 32); j++) { -+ tmp = pdu_io_read32(state->base + -+ NIST_TRNG_EDU_VRAND_0 + j); -+ /* copy to random_bits byte-by-byte, until req_num_bytes are copied */ -+ remained_bytes = req_num_bytes - -+ (i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4); -+ if (remained_bytes > 4) { -+ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, 4); -+ -+ /* decrement the bits counter and return error if generated more than the maximum*/ -+ state->counters.bits_per_req_left = -+ state->counters.bits_per_req_left - -+ 4 * 8; -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ } else { -+ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, remained_bytes); -+ -+ /* decrement the bits counter and return error if generated more than the maximum*/ -+ state->counters.bits_per_req_left = -+ state->counters.bits_per_req_left - -+ remained_bytes * 8; -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ break; -+ } -+ } -+ } -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_rgmii1_driving>; ++}; + -+/* Generate */ -+int nisttrng_generate(struct nist_trng_state *state, void *random_bits, -+ unsigned long req_num_bytes, int req_sec_strength, -+ int pred_resist, void *addin_str) -+{ -+ int err; -+ int reseed_required; ++#if 0 // Default to disable RC & SGMII ++#define PCIE2_RC 1 // 1: RC, 0: SGMII ++#if PCIE2_RC ++&pcie2 { ++ status = "okay"; ++}; ++#else ++&mdio2 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; + -+ DEBUG(">> %s: requested number of bytes = %lu, security strength = %u, pred_resist = %u, additional string existence = %u\n", -+ __func__, req_num_bytes, req_sec_strength, pred_resist, -+ (addin_str) ? 1 : 0); ++ ethphy2: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++&sgmii { ++ status = "okay"; ++}; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++&mac2 { ++ status = "okay"; + -+ /* if the DRBG is not instantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ SYNHW_PRINT("DRBG is not instantiated\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ phy-mode = "sgmii"; ++ phy-handle = <ðphy2>; ++}; ++#endif ++#endif + -+ /* requested number of bits has to be less that the programmed maximum */ -+ if ((req_num_bytes * 8) > state->counters.max_bits_per_req) { -+ SYNHW_PRINT("requested number of bits (%lu) is larger than the set maximum (%lu)\n", -+ (req_num_bytes * 8), state->counters.max_bits_per_req); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&espi0 { ++ status = "okay"; ++ perif-dma-mode; ++ perif-mmbi-enable; ++ perif-mmbi-src-addr = <0x0 0xa8000000>; ++ perif-mmbi-tgt-memory = <&espi0_mmbi_memory>; ++ perif-mmbi-instance-num = <0x1>; ++ perif-mcyc-enable; ++ perif-mcyc-src-addr = <0x0 0x98000000>; ++ perif-mcyc-size = <0x0 0x10000>; ++ memory-region = <&espi0_mcyc_memory>; ++ perif-rtc-enable; ++ vw-pltrst-monitor; ++ oob-dma-mode; ++ flash-dma-mode; ++#if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten ++ flash-edaf-mode = <0x0>; ++ flash-edaf-tgt-addr = <&edaf0>; ++#endif ++}; + -+ /* security strength has to be lower than what the DRBG is instantiated with. set_sec_strength function checks this. */ -+ err = nisttrng_set_sec_strength(state, req_sec_strength); -+ if (err) -+ goto ERR; ++&rtc_over_espi0 { ++ status = "okay"; ++}; + -+ /* set the prediction resistance - if pred_resist is set but, pred_resist that the DRBG is instantiated with is not 1, return error */ -+ err = nisttrng_set_pred_resist(state, pred_resist); -+ if (err) -+ goto ERR; ++/* Enable UART2 and UART9 for obmc-console. */ ++&uart2 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ /* make sure random_bits is not NULL */ -+ if (!random_bits) { -+ DEBUG("random_bits pointer cannot be NULL\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&uart9 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ /* set the reseed required flag to 0. The loop is to check at the end whether a reseed is required at the end and jump back to reseed and generate if needed. This is the NIST mandated procedure */ -+ reseed_required = 0; ++#if DUAL_NODE ++&espi1 { ++ status = "okay"; ++ perif-dma-mode; ++ perif-mmbi-enable; ++ perif-mmbi-src-addr = <0x0 0xa8000000>; ++ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; ++ perif-mmbi-instance-num = <0x1>; ++ perif-mcyc-enable; ++ perif-mcyc-src-addr = <0x0 0x98000000>; ++ perif-mcyc-size = <0x0 0x10000>; ++ perif-rtc-enable; ++ vw-pltrst-monitor; ++ oob-dma-mode; ++ flash-dma-mode; ++#if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten ++ flash-edaf-mode = <0x0>; ++ flash-edaf-tgt-addr = <&edaf1>; ++#endif ++}; + -+ if (!addin_str) { -+ /* set the ADDIN_PRESENT field of the MODE register to 1 */ -+ err = nisttrng_set_addin_present(state, 0); -+ if (err) -+ goto ERR; -+ } ++&rtc_over_espi1 { ++ status = "okay"; ++}; + -+ do { -+ void *generate_addin_str = addin_str; ++/* Enable UART7 and UART10 for obmc-console. */ ++&uart7 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; + -+ if (pred_resist | reseed_required) { -+ err = nisttrng_reseed(state, pred_resist, addin_str); -+ if (err) -+ goto ERR; ++&uart10 { ++ /delete-property/ pinctrl-names; ++ /delete-property/ pinctrl-0; ++ status = "okay"; ++}; ++#endif /* DUAL_NODE */ + -+ /* SP800-90a says that if reseed is executed, any additional input string is only used in the reseed phase and replaced by NULL in the generate phase */ -+ generate_addin_str = NULL; -+ err = nisttrng_set_addin_present(state, 0); -+ if (err) -+ goto ERR; ++&lpc0_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0xca0>; ++ kcs-channel = <0>; ++}; + -+ /* ADDIN_PRESENT field in MODE has to be set back to 0 to avoid illegal cmd sequence */ -+ reseed_required = 0; -+ } ++&lpc0_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0xca8>; ++ kcs-channel = <1>; ++}; + -+ /* generate process */ -+ if (nisttrng_check_seed_lifetime(state) == CRYPTO_RESEED_REQUIRED) { -+ reseed_required = 1; ++&lpc0_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0xca2>; ++ kcs-channel = <2>; ++}; + -+ } else { -+ reseed_required = 0; ++&lpc0_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0xca4>; ++ kcs-channel = <3>; ++}; + -+ /* Refresh_Addin command if additional input is not NULL*/ -+ if (generate_addin_str) { -+ err = nisttrng_refresh_addin(state, generate_addin_str); -+ if (err) -+ goto ERR; -+ } ++&lpc0_ibt { ++ status = "okay"; ++}; + -+ /* Generate all random bits */ -+ /* if EDU present then get random number from private vtrng */ ++&lpc0_mbox { ++ status = "okay"; ++}; + -+ //state->config.build_cfg0.edu_present = 0; -+ if (state->config.build_cfg0.edu_present) { -+ err = nisttrng_generate_private_vtrng(state, random_bits, -+ req_num_bytes); -+ if (err) -+ goto ERR; ++#if 1 ++&lpc0_snoop { ++ status = "okay"; ++ snoop-ports = <0x80>, <0x81>; ++}; ++#else ++&lpc0_pcc { ++ status = "okay"; ++ pcc-ports = <0x80>; ++}; ++#endif + -+ } else { -+ err = nisttrng_gen_random(state, random_bits, -+ req_num_bytes); -+ if (err) -+ goto ERR; -+ -+ /* Advance the state - if it returns CRYPTO_RESEED_REQUIRED, have to jump back and do a reseed and generate */ -+ err = nisttrng_advance_state(state); -+ if (err) -+ goto ERR; -+ } -+ } -+ } while (reseed_required); ++&lpc0_uart_routing { ++ status = "okay"; ++}; + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_GENERATE; -+ERR: -+ if (err) -+ random_bits = NULL; ++&lpc1_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0xca0>; ++ kcs-channel = <4>; ++}; + -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_generate */ -+EXPORT_SYMBOL(nisttrng_generate); -diff --git a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c ---- a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c 2025-12-23 10:16:19.525059469 +0000 -@@ -0,0 +1,1022 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * This Synopsys software and associated documentation (hereinafter the -+ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless -+ * otherwise expressly agreed to in writing between Synopsys and you. The -+ * Software IS NOT an item of Licensed Software or a Licensed Product under -+ * any End User Software License Agreement or Agreement for Licensed Products -+ * with Synopsys or any supplement thereto. Synopsys is a registered trademark -+ * of Synopsys, Inc. Other names included in the SOFTWARE may be the -+ * trademarks of their respective owners. -+ * -+ * The contents of this file are dual-licensed; you may select either version -+ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license -+ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the -+ * SOFTWARE. The BSD License is copied below. -+ * -+ * BSD-3-Clause License: -+ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions, and the following disclaimer, without -+ * modification. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * 3. The names of the above-listed copyright holders may not be used to -+ * endorse or promote products derived from this software without specific -+ * prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+ * POSSIBILITY OF SUCH DAMAGE. -+ */ ++&lpc1_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0xca8>; ++ kcs-channel = <5>; ++}; + -+#include "nisttrng_hw.h" -+#include "nisttrng.h" ++&lpc1_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0xca2>; ++ kcs-channel = <6>; ++}; + -+/* Wait functions */ -+static int nisttrng_wait_on_(struct nist_trng_state *state, u32 mask) -+{ -+ u32 tmp; -+ int t; -+ -+ t = NIST_TRNG_RETRY_MAX; ++&lpc1_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0xca4>; ++ kcs-channel = <7>; ++}; + -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ISTAT); -+ } while (!(tmp & (mask | NIST_TRNG_REG_ISTAT_ALARMS)) && --t); ++&lpc1_ibt { ++ status = "okay"; ++}; + -+ if (tmp & NIST_TRNG_REG_ISTAT_ALARMS) -+ return nisttrng_get_alarms(state); ++&lpc1_mbox { ++ status = "okay"; ++}; + -+ if (t) { -+ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, mask); -+ return CRYPTO_OK; ++#if 1 ++&lpc1_snoop { ++ status = "okay"; ++ snoop-ports = <0x80>, <0x81>; ++}; ++#else ++&lpc1_pcc { ++ status = "okay"; ++ pcc-ports = <0x80>; ++}; ++#endif + -+ } else { -+ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", -+ (unsigned long)tmp); -+ return CRYPTO_TIMEOUT; -+ } -+} /* nisttrng_wait_on_ */ ++&lpc1_uart_routing { ++ status = "okay"; ++}; + -+int nisttrng_wait_on_done(struct nist_trng_state *state) -+{ -+ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_DONE); -+} /* nisttrng_wait_on_done */ -+EXPORT_SYMBOL(nisttrng_wait_on_done); ++#if 1 ++&video0 { ++ status = "okay"; ++ memory-region = <&video_engine_memory0>; ++}; + -+int nisttrng_wait_on_noise_rdy(struct nist_trng_state *state) -+{ -+ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_NOISE_RDY); -+} /* nisttrng_wait_on_noise_rdy */ ++&video1 { ++ status = "okay"; ++ memory-region = <&video_engine_memory1>; ++}; ++#else ++&rvas0{ ++ status = "okay"; ++ memory-region = <&rvas_memory0>; ++}; + -+static int nisttrng_wait_on_zeroize(struct nist_trng_state *state) -+{ -+ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_ZEROIZE); -+} /* nisttrng_wait_on_zeroize */ ++&rvas1{ ++ status = "okay"; ++ memory-region = <&rvas_memory1>; ++}; ++#endif + -+static int nisttrng_wait_on_kat_completed(struct nist_trng_state *state) -+{ -+ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_KAT_COMPLETE); -+} /* nisttrng_wait_on_kat_completed */ ++&disp_intf { ++ status = "okay"; ++}; + -+int nisttrng_wait_on_busy(struct nist_trng_state *state) -+{ -+ u32 tmp, t; ++&rtc { ++ status = "okay"; ++}; + -+ t = NIST_TRNG_RETRY_MAX; ++&rsss { ++ status = "okay"; ++}; + -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); -+ } while ((tmp & NIST_TRNG_REG_STAT_BUSY) && --t); -+ -+ if (t) -+ return CRYPTO_OK; -+ -+ SYNHW_PRINT("wait_on_busy: failed timeout: %08lx\n", -+ (unsigned long)tmp); -+ return CRYPTO_TIMEOUT; -+} /* nisttrng_wait_on_busy */ -+EXPORT_SYMBOL(nisttrng_wait_on_busy); -+ -+/* Read and return alarm. Zeroize if there is an alarm*/ -+int nisttrng_get_alarms(struct nist_trng_state *state) -+{ -+ u32 tmp; -+ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ISTAT); -+ if (tmp & NIST_TRNG_REG_ISTAT_ALARMS) { -+ // alarm happened -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ALARM); -+ DEBUG("Received alarm: %lx\n", (unsigned long)tmp); -+ // clear istat -+ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, -+ NIST_TRNG_REG_ISTAT_ALARMS); -+ pdu_io_write32(state->base + NIST_TRNG_REG_ALARM, 0x1F); -+ state->status.alarm_code = tmp & 0x1F; -+ -+ /* zeroize if there was an alarm */ -+ if (state->status.alarm_code != -+ NIST_TRNG_REG_ALARM_FAILED_TEST_ID_OK) { -+ nisttrng_zeroize(state); -+ } -+ } else { -+ state->status.alarm_code = 0; -+ } ++&ecdsa { ++ status = "okay"; ++}; + -+ if (state->status.alarm_code) -+ return CRYPTO_FATAL; -+ else -+ return CRYPTO_OK; -+} /* nisttrng_get_alarms */ -+EXPORT_SYMBOL(nisttrng_get_alarms); ++&hace { ++ dummy-key0 = < ++ 0x89878915 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key1 = < ++ 0x89878902 0x1DA242FA 0x1A7885CE 0x5BD7FA39 ++ 0xC53265FD 0xCC346B25 0x230370EE 0xD0570629 ++ >; ++ dummy-key2 = < ++ 0x2C914FA3 0x1056D87B 0xC13D6AE2 0x5E44AF98 ++ 0x0DB97321 0xCA378CF6 0x62EE115D 0x3FA74B90 ++ >; ++ dummy-key3 = < ++ 0x9E18D25C 0x6FB17A43 0x348DE520 0x1269FAC7 ++ 0xAC5503DE 0x2DB61F88 0xEF9AC074 0xB84E6731 ++ >; ++ status = "okay"; ++}; + -+/* Reset reminder and alarm counters */ -+int nisttrng_reset_counters(struct nist_trng_state *state) -+{ -+ state->counters.bits_per_req_left = state->counters.max_bits_per_req; -+ state->counters.req_per_seed_left = state->counters.max_req_per_seed; ++#if PCIE0_EP ++&bmc_dev0 { ++ status = "okay"; ++ memory-region = <&bmc_dev0_memory>; ++}; + -+ return 0; -+} /* nisttrng_reset_counters */ -+EXPORT_SYMBOL(nisttrng_reset_counters); ++&xdma0 { ++ status = "okay"; ++ memory-region = <&xdma_memory0>; ++}; + -+/* When a zeroize happens some of the struct objects should reset */ -+int nisttrng_reset_state(struct nist_trng_state *state) -+{ -+ nisttrng_reset_counters(state); -+ state->status.pad_ps_addin = 0; -+ state->status.current_state = NIST_TRNG_STATE_UNINSTANTIATE; ++&pcie_vuart0 { ++ port = <0x3f8>; ++ sirq = <4>; ++ sirq-polarity = <0>; + -+ return 0; -+} /* nisttrng_reset_state */ ++ status = "okay"; ++}; + -+/* ---------- Set field APIs ---------- */ ++&pcie_vuart1 { ++ port = <0x2f8>; ++ sirq = <3>; ++ sirq-polarity = <0>; + -+/* -+ * Sets the security strength of the DRBG instance. -+ * > req_sec_strength has to be an integer. The API chooses one of SEC_STRNT_AES128 or SEC_STRNT_AES256 as follows: -+ * 0 < req_sec_strength <= 128 --> security strength = SEC_STRNT_AES128 -+ * 128 < req_sec_strength <= 256 --> security strength = SEC_STRNT_AES256 -+ * else --> Invalid security strength -+ * > If the DRBG is instantiated, a new security strength change request with greater security strength will return error. -+ */ -+int nisttrng_set_sec_strength(struct nist_trng_state *state, int req_sec_strength) -+{ -+ int err; -+ u32 tmp; -+ enum nisttrng_sec_strength chosen_sec_strength; ++ status = "okay"; ++}; + -+ DEBUG(">> %s: security strength = %i\n", __func__, -+ req_sec_strength); ++&pcie_lpc0_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0x3a0>; ++ kcs-channel = <8>; ++}; + -+ /* choose the security strength */ -+ /* set the security strength to the lowest security strength greater or equal to the req_sec_strenght from the set {128, 256} */ -+ if (REQ_SEC_STRENGTH_IS_VALID(req_sec_strength)) { -+ if (req_sec_strength > 0 && req_sec_strength <= 128) { -+ chosen_sec_strength = SEC_STRNT_AES128; ++&pcie_lpc0_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0x3a8>; ++ kcs-channel = <9>; ++}; + -+ } else if (((req_sec_strength > 128) && -+ (req_sec_strength <= 256)) && -+ (state->config.features.drbg_arch == AES256)) { -+ chosen_sec_strength = SEC_STRNT_AES256; ++&pcie_lpc0_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0x3a2>; ++ kcs-channel = <10>; ++}; + -+ } else { /* should not get here, because we have already checked the validity */ -+ DEBUG("Invalid security strength\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ } else { -+ DEBUG("Invalid security strength\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ DEBUG("chosen security strength = %u\n", chosen_sec_strength); -+ -+ /* set the security strenght - at this point security strength is validated and converted */ -+ if (DRBG_INSTANTIATED(state->status.current_state) && -+ chosen_sec_strength != state->status.sec_strength) { -+ /* security strength can only change when the DRBG is not instantiated. */ -+ /* if the new security strength is less that what the DRBG is instantiated with, accept it, but don't change in HW. If it's more, return error */ -+ if (chosen_sec_strength < state->status.sec_strength) { -+ DEBUG("Lowering the security strength. DRBG is already instantiated.\n"); -+ state->status.pad_ps_addin = 4; -+ state->status.sec_strength = chosen_sec_strength; ++&pcie_lpc0_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0x3a4>; ++ kcs-channel = <11>; ++}; + -+ } else { -+ state->status.pad_ps_addin = 0; -+ DEBUG("Cannot select a higher security strenght once the DRBG is instantiated\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ } else { -+ DEBUG("Updating the security strength.\n"); -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); -+ tmp = NIST_TRNG_REG_MODE_SET_SEC_ALG(tmp, chosen_sec_strength); -+ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++&pcie_lpc0_ibt { ++ status = "okay"; ++ bt-channel = <2>; ++}; + -+ state->status.pad_ps_addin = 0; -+ state->status.sec_strength = chosen_sec_strength; -+ } ++&pcie0_mmbi0 { ++ status = "okay"; ++ memory-region = <&pcie0_mmbi0_memory>; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_sec_strength */ -+EXPORT_SYMBOL(nisttrng_set_sec_strength); ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ ++}; ++#else /* !PCIE0_EP */ ++&pcie0 { ++ status = "okay"; ++}; ++#endif /* PCIE0_EP */ + -+/* -+ * Sets the ADDIN_PRESENT field of the MODE register according to the addin_present input. -+ */ -+int nisttrng_set_addin_present(struct nist_trng_state *state, int addin_present) -+{ -+ u32 tmp; ++#if PCIE1_EP ++&bmc_dev1 { ++ status = "okay"; ++ memory-region = <&bmc_dev1_memory>; ++}; + -+ DEBUG(">> %s, adding_present = %u\n", __func__, -+ addin_present); ++&xdma1 { ++ status = "okay"; ++ memory-region = <&xdma_memory1>; ++}; + -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); -+ tmp = NIST_TRNG_REG_MODE_SET_ADDIN_PRESENT(tmp, addin_present); -+ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++&pcie_vuart2 { ++ port = <0x3f8>; ++ sirq = <4>; ++ sirq-polarity = <0>; + -+ DEBUG("--- Return %s, err = %i\n", __func__, 0); -+ return 0; -+} /* nisttrng_set_addin_present */ -+EXPORT_SYMBOL(nisttrng_set_addin_present); ++ status = "okay"; ++}; + -+/* -+ * Sets the PRED_RESIST field of the MODE register according to the pred_resist input. -+ * > If the DRBG is instantiated with prediction resistance of 0, and a change to the prediction resistance of 1 is requested, -+ * the API will return an error. -+ */ -+int nisttrng_set_pred_resist(struct nist_trng_state *state, int pred_resist) -+{ -+ int err; -+ u32 tmp; ++&pcie_vuart3 { ++ port = <0x2f8>; ++ sirq = <3>; ++ sirq-polarity = <0>; + -+ DEBUG(">> %s: pred_resist = %u\n", __func__, pred_resist); ++ status = "okay"; ++}; + -+ /* if DRBG is instantiated, prediction resistance can only change from 1 to 0 and not vice versa. This is a NIST requirement. */ -+ if (DRBG_INSTANTIATED(state->status.current_state) && pred_resist && -+ !state->status.pred_resist) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&pcie_lpc1_kcs0 { ++ status = "okay"; ++ kcs-io-addr = <0x3a0>; ++ kcs-channel = <12>; ++}; + -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); -+ tmp = NIST_TRNG_REG_MODE_SET_PRED_RESIST(tmp, pred_resist); -+ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++&pcie_lpc1_kcs1 { ++ status = "okay"; ++ kcs-io-addr = <0x3a8>; ++ kcs-channel = <13>; ++}; + -+ state->status.pred_resist = pred_resist; ++&pcie_lpc1_kcs2 { ++ status = "okay"; ++ kcs-io-addr = <0x3a2>; ++ kcs-channel = <14>; ++}; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_pred_resist */ -+EXPORT_SYMBOL(nisttrng_set_pred_resist); ++&pcie_lpc1_kcs3 { ++ status = "okay"; ++ kcs-io-addr = <0x3a4>; ++ kcs-channel = <15>; ++}; + -+/* -+ * Puts the NIST_TRNG in either the SECURE or PROMISCUOUS mode. -+ * > A value of 1 for secure_mode puts the core in the SECURE mode and a value of 0 puts it in the PROMISCUOUS mode. -+ * > Any change to the secure mode of the NIST_TRNG will result in a complete zeroize, and will set the seeding mode to self-seeding. -+ * A zeroize will not destroy the programmed mode and ALARM register value. -+ * It keeps the programmed mode to avoid re-programming. -+ * It also, maintains the ALARM register value, so that the user can read the value to understand the reason of the occurred alarm. -+ */ -+int nisttrng_set_secure_mode(struct nist_trng_state *state, int secure_mode) -+{ -+ int err; -+ u32 tmp; -+ int t; ++&pcie_lpc1_ibt { ++ status = "okay"; ++ bt-channel = <3>; ++}; + -+ DEBUG(">> %s: secure_mode = %u\n", __func__, secure_mode); ++&pcie1_mmbi4 { ++ status = "okay"; ++ memory-region = <&pcie1_mmbi4_memory>; + -+ t = NIST_TRNG_RETRY_MAX; ++ noi = <7>; ++ aspeed,mmbi-interface = "mctp-netdev", /* ch0 */ ++ "ioctl", /* ch1 */ ++ "ioctl", /* ch2 */ ++ "ioctl", /* ch3 */ ++ "ioctl", /* ch4 */ ++ "ioctl", /* ch5 */ ++ "ioctl"; /* ch6 */ ++}; ++#else /* !PCIE1_EP */ ++&pcie1 { ++ status = "okay"; ++}; ++#endif /* PCIE1_EP */ + -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_SMODE); -+ tmp = NIST_TRNG_REG_SMODE_SET_SECURE_EN(tmp, secure_mode); -+ pdu_io_write32(state->base + NIST_TRNG_REG_SMODE, tmp); ++&sdio_controller { ++ status = "okay"; ++ mmc-hs200-1_8v; + -+ /* wait until STAT register indicates that the mode is applied */ -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); -+ } while ((NIST_TRNG_REG_STAT_GET_SECURE(tmp) != secure_mode) && --t); ++ vcc_sdhci0: regulator-vcc-sdhci0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "SDHCI0 Vcc"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpios = <&gpio1 ASPEED_GPIO(G, 6) GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; + -+ if (!t) { -+ err = CRYPTO_TIMEOUT; -+ goto ERR; -+ } ++ vccq_sdhci0: regulator-vccq-sdhci0 { ++ compatible = "regulator-gpio"; ++ regulator-name = "SDHCI0 VccQ"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ gpios = <&gpio1 ASPEED_GPIO(G, 7) GPIO_ACTIVE_HIGH>; ++ gpios-states = <1>; ++ states = <3300000 1>, ++ <1800000 0>; ++ }; ++}; + -+ /* if secure mode changes, a zeroize will happen in HW. */ -+ if (state->status.secure_mode != secure_mode) { -+ DEBUG("secure mode changed. zeroize happened. reset sw state\n"); -+ /* nonce mode goes back to default. */ -+ state->status.nonce_mode = 0; -+ /* reset the SW state */ -+ nisttrng_reset_state(state); -+ } ++&sdhci { ++ status = "okay"; ++ bus-width = <4>; ++ max-frequency = <125000000>; ++ /* DDR50 bits in CAPA2 are not supported */ ++ sdhci-caps-mask = <0x6 0x0>; ++ sdhci-drive-type = /bits/ 8 <3>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sd_default>; ++ vmmc-supply = <&vcc_sdhci0>; ++ vqmmc-supply = <&vccq_sdhci0>; ++ sd-uhs-sdr104; /* enable sdr104 to execute tuning */ ++}; + -+ state->status.secure_mode = secure_mode; ++#if 1 ++&i2c0 { ++ status = "okay"; ++}; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_secure_mode */ -+EXPORT_SYMBOL(nisttrng_set_secure_mode); ++&i2c1 { ++ status = "okay"; ++}; + -+/* -+ * To change the seeding mode of the NIST_TRNG. -+ * > A value of 1 for nonce_mode will put the NIST_TRNG in the nonce seeding mode, which means that the seed will be provided by the user, -+ * unlike the noise or self-seeding mode (normal mode of operation) in which the seed is generated by the internal entropy source. -+ * > Any transition to or from the nonce mode will zeroize the NIST_TRNG. -+ */ -+int nisttrng_set_nonce_mode(struct nist_trng_state *state, int nonce_mode) -+{ -+ int err; -+ u32 tmp; -+ int t; ++&i2c2 { ++ status = "okay"; ++}; + -+ DEBUG(">> %s: nonce_mode = %u\n", __func__, nonce_mode); ++&i2c3 { ++ status = "okay"; ++}; + -+ t = NIST_TRNG_RETRY_MAX; ++&i2c4 { ++ status = "okay"; ++}; + -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_SMODE); -+ tmp = NIST_TRNG_REG_SMODE_SET_NONCE(tmp, nonce_mode); -+ pdu_io_write32(state->base + NIST_TRNG_REG_SMODE, tmp); ++&i2c5 { ++ status = "okay"; ++}; + -+ /* wait until STAT register indicates that the mode is applied */ -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); -+ } while ((NIST_TRNG_REG_STAT_GET_NONCE(tmp) != nonce_mode) && --t); ++&i2c6 { ++ status = "okay"; ++}; + -+ if (!t) { -+ err = CRYPTO_TIMEOUT; -+ goto ERR; -+ } ++&i2c7 { ++ status = "okay"; ++}; + -+ /* if nonce mode changes, a zeroize will happen in HW. */ -+ if (state->status.nonce_mode != nonce_mode) { -+ DEBUG("nonce mode changed. zeroize happened. reset sw state\n"); -+ /* reset the SW state */ -+ nisttrng_reset_state(state); -+ } ++&i2c8 { ++ status = "okay"; ++}; + -+ state->status.nonce_mode = nonce_mode; ++&i2c11 { ++ status = "okay"; ++}; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_nonce_mode */ -+EXPORT_SYMBOL(nisttrng_set_nonce_mode); ++&i2c12 { ++ status = "okay"; ++}; + -+/* ---------- Load data APIs ---------- */ -+/* -+ * Loads the additional input or personalization string into the NPA_DATAx registers. -+ * > Loads the proper number of bits (256 or 384) according to the security strength stored in the state handle. -+ */ -+int nisttrng_load_ps_addin(struct nist_trng_state *state, void *input_str) -+{ -+ int err; -+ int i, j; -+ int str_size; ++&i2c13 { ++ status = "okay"; ++}; ++#endif + -+ DEBUG(">> %s starts...\n", __func__); ++#if 0 ++&ehci0 { ++ status = "okay"; ++}; + -+ /* return error if the pointer is NULL */ -+ if (!input_str) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&ehci1 { ++ status = "okay"; ++}; + -+ /* calculate the length based on the security strength */ -+ if (state->status.sec_strength == SEC_STRNT_AES128) -+ str_size = 8; /* 256/32 */ -+ else if (state->status.sec_strength == SEC_STRNT_AES256) -+ str_size = 12; /* 384/32 */ ++&uhci0 { ++ status = "okay"; ++ memory-region = <&uhci0_reserved>; ++}; + -+ for (i = 0; i < str_size; i++) { -+ pdu_io_write32(state->base + NIST_TRNG_REG_NPA_DATA0 + i, -+ ((u32 *)input_str)[i]); -+ } ++#endif + -+ j = str_size + state->status.pad_ps_addin; -+ /* if security strength is lowered after the DRBG is instantiated, pad PS and ADDIN with 0 at the MSB side */ -+ DEBUG("pad NPA_DATA with %u zeros at the MSB side\n", -+ state->status.pad_ps_addin); -+ for (i = str_size; i < j; i++) -+ pdu_io_write32(state->base + NIST_TRNG_REG_NPA_DATA0 + i, 0); ++#if 0 ++&uphy3a { ++ status = "okay"; ++}; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_load_ps_addin */ -+EXPORT_SYMBOL(nisttrng_load_ps_addin); ++&uphy3b { ++ status = "okay"; ++}; ++#endif + -+/* ---------- Command APIs ---------- */ -+/* -+ * Provides entropy and is used in both nonce and noise (self) seeding modes of operation: -+ * > If the NIST_TRNG is in the nonce mode, entropy must be provided by the user; otherwise (in the self-seeding mode) entropy will be generated by the internal entropy source of the NIST_TRNG. -+ * > In the noise mode, calling the API will initiate a seeding command. Depending on the programmed security strength, a 256 or 384-bit seed will be generated. -+ * > Inputs 2 and 3 are only used when the core is in the nonce mode. -+ * > In the nonce mode, the NIST_TRNG can be seeded either through 2 or 3 blocks of 512-bit nonce values which are passed to the internal derivation function to increase the entropy, -+ * or it can be seeded by a 256 or 384-bit nonce written directly into the SEEDx registers. -+ * Passing a value of 1 to nonce_operation selects the former scenario and a value of 0 selects the latter. -+ * > The input_nonce pointer must point to a memory location with a sufficient number of initialized bits. -+ * > Table below shows the required number of bits depending on the nonce_operation and the security strength values. -+ * nonce_operation | Security Strength | Bit length requirement -+ * ------------------------------------------------------------------------------------------ -+ * 1 (using the Derivation Function) | SEC_STRNT_AES128 | 2x512 = 1024 -+ * 1 (using the Derivation Function) | SEC_STRNT_AES256 | 3x512 = 1536 -+ * 0 (loading the seed into SEEDx) | SEC_STRNT_AES128 | 256 -+ * 0 (loading the seed into SEEDx) | SEC_STRNT_AES256 | 384 -+ * > Generated entropy is secret information held securely within the HW and remains inaccessible to the user, unless the HW core is in the PROMISCUOUS mode. -+ */ -+int nisttrng_get_entropy_input(struct nist_trng_state *state, void *input_nonce, -+ int nonce_operation) -+{ -+ int err; -+ int nonce_ld_cntr = 0; -+ int i, j; ++#if 0 ++&xhci0 { ++ status = "okay"; ++}; + -+ DEBUG(">> %s: seeding mode = %s, nonce_operation = %u\n", __func__, -+ (state->status.nonce_mode ? "Nonce" : "Noise"), nonce_operation); ++&xhci1 { ++ status = "okay"; ++}; ++#endif + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++&vhuba0 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; ++}; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++&vhubb1 { ++ status = "okay"; ++}; + -+ /* --- Seeding --- */ -+ if (state->status.nonce_mode) { /* --- nonce mode --- */ -+ if (!input_nonce) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&vhubc { ++ status = "okay"; ++#if 0 ++ pinctrl-0 = <&pinctrl_usb2cud_default>; ++ aspeed,uart-ports = <12>; ++#endif ++}; + -+ nonce_ld_cntr = 0; ++&ehci3 { ++ status = "okay"; ++}; + -+ if (state->status.sec_strength == SEC_STRNT_AES128) -+ nonce_ld_cntr = 2; -+ else if (state->status.sec_strength == SEC_STRNT_AES256) -+ nonce_ld_cntr = 3; ++&uhci1 { ++ status = "okay"; ++ memory-region = <&uhci1_reserved>; ++}; + -+ if (nonce_operation) { /* load the noise inside NPA_DATAx register and issue gen_nonce command */ -+ for (i = 0; i < nonce_ld_cntr; i++) { -+ /* load the nonoce */ -+ for (j = 0; j < 16; j++) { -+ pdu_io_write32(state->base + -+ NIST_TRNG_REG_NPA_DATA0 + j, -+ ((u32 *)input_nonce)[16 * i + j]); -+ } ++&wdt0 { ++ status = "okay"; ++}; + -+ /* issue the command and wait on done */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_GEN_NONCE); ++&wdt1 { ++ status = "okay"; ++}; + -+ if (nisttrng_wait_on_done(state)) { -+ err = CRYPTO_FATAL; -+ goto ERR; -+ }; -+ } ++&otp { ++ status = "okay"; ++}; + -+ } else { -+ /* load the nonoce */ -+ for (i = 0; i < 4 * nonce_ld_cntr; i++) { -+ pdu_io_write32(state->base + NIST_TRNG_REG_SEED0 + i, -+ ((u32 *)input_nonce)[i]); -+ } -+ } -+ } else { /* --- noise mode --- */ -+ /* issue the command and wait on done */ -+ DEBUG("issue the Gen_Noise command\n"); -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_GEN_NOISE); ++#if 0 ++&soc0 { ++ mbox-ssp-0 { ++ compatible = "aspeed,aspeed-mbox"; ++ reg = <0x4 0x31480000 0x0 0x200000>, <0x0 0x10001000 0x0 0x1000>; ++ mboxes = <&mbox0 0>; ++ aspeed,tx-timeout = <100>; ++ }; ++}; ++#endif + -+ if (nisttrng_wait_on_done(state)) { -+ err = CRYPTO_FATAL; -+ goto ERR; -+ }; -+ } ++#if 1 ++&soc0 { ++ mbox-bootmcu-1 { ++ compatible = "aspeed,aspeed-mbox"; ++ reg = <0x4 0x31880000 0x0 0x100000>, <0x4 0x31980000 0x0 0x100000>; ++ mboxes = <&mbox2 1>; ++ aspeed,tx-timeout = <10000>; ++ }; ++}; ++#endif +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts 2026-09-09 15:51:27.104504234 +0000 +@@ -0,0 +1,48 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_get_entropy_input */ -+EXPORT_SYMBOL(nisttrng_get_entropy_input); ++/dts-v1/; + -+/* -+ * Generate Function: -+ * > The Generate function in NIST_TRNG HW is broken down into 3 steps: Refresh_Addin, Gen_Random and Advance_State. -+ * nisttrng_generate incorporates all these steps and some extra checks into one simple API. -+ * > There is one API for each step, below || -+ * \/ -+ */ -+/* -+ * Generate Part 1 - Refresh_Addin: Additional input string is used to add to the HW state entropy. -+ * > This API calls nisttrng_set_addin_present to set the ADDIN_PRESENT field of the MODE register to 1. -+ * > Then it loads the additional input provided by addin_str pointer into the NPA_DATAx by calling the nisttrng_load_ps_addin. -+ * > Then, it issues a Refresh_Addin command to the HW. -+ * > If the addin_str pointer is NULL, the API will return error. -+ */ -+int nisttrng_refresh_addin(struct nist_trng_state *state, void *addin_str) -+{ -+ int err; ++#include "ast2700a1-evb.dts" + -+ DEBUG(">> %s starts...\n", __func__); ++/ { ++ model = "AST2700A1-NCSI"; ++}; + -+ /* if the DRBG is not intantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++&sgpios { ++ status = "disabled"; ++}; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++&mac0 { ++ status = "okay"; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++ phy-mode = "rmii"; ++ use-ncsi; + -+ /* This API should not be called with a NULL additional input string */ -+ if (!addin_str) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ pinctrl-names = "default"; ++ /* If you want to use RMII0 RCLKO as internal clock for RMII, ++ * add &pinctrl_rmii0_rclko_default in pinctrl-0. ++ */ ++ pinctrl-0 = <&pinctrl_rmii0_default>; ++}; + -+ /* set the ADDIN_PRESENT field of the MODE register to 1 */ -+ err = nisttrng_set_addin_present(state, 1); -+ if (err) -+ goto ERR; ++&mac1 { ++ status = "okay"; + -+ err = nisttrng_load_ps_addin(state, addin_str); -+ if (err) -+ goto ERR; ++ phy-mode = "rmii"; ++ use-ncsi; + -+ /* execute the command and wait on done*/ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_REFRESH_ADDIN); ++ pinctrl-names = "default"; ++ /* If you want to use RMII1 RCLKO as internal clock for RMII, ++ * add &pinctrl_rmii1_rclko_default in pinctrl-0. ++ */ ++ pinctrl-0 = <&pinctrl_rmii1_default>; ++}; + -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; ++&syscon1 { ++ mac0-clk-delay = <0 0 ++ 0 0 ++ 0 0>; ++ mac1-clk-delay = <0 0 ++ 0 0 ++ 0 0>; ++}; +diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts +--- a/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts 1970-01-01 00:00:00.000000000 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts 2026-09-09 15:51:27.104504234 +0000 +@@ -0,0 +1,220 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+ err = 0; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_refresh_addin */ -+EXPORT_SYMBOL(nisttrng_refresh_addin); ++/dts-v1/; + -+/* -+ * Generate Part 2 - Gen_Random: generates the requested number of bits. -+ * > This API issues the Gen_Random command to the HW as many times as indicated by req_num_bytes to generate the requested number of bits. -+ * > If the requested number of bits (i.e. 128×req_num_blks) is more than the maximum value specified by max_bits_per_req, the API will return error. -+ * > Random bits will be returned in random_bits. -+ */ -+int nisttrng_gen_random(struct nist_trng_state *state, void *random_bits, -+ unsigned long req_num_bytes) -+{ -+ int err; -+ int i, j; -+ u32 tmp; -+ unsigned int remained_bytes; -+ unsigned long req_num_blks; ++#include "ast2700a1-evb.dts" + -+ DEBUG(">> %s: req_num_bytes = %lu\n", __func__, req_num_bytes); ++&fmc { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_fwspi_quad_default>; ++ pinctrl-names = "default"; + -+ /* if the DRBG is not intantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "bmc"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++#include "aspeed-evb-flash-layout-128.dtsi" ++ }; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ flash@1 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "fmc0:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; -+ -+ /* requested number of bits has to be less that the programmed maximum */ -+ if ((req_num_bytes * 8) > state->counters.max_bits_per_req) { -+ DEBUG("requested number of bits (%lu) is larger than the set maximum (%lu)\n", -+ (req_num_bytes * 8), state->counters.max_bits_per_req); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ /* make sure random_bits is not NULL */ -+ if (!random_bits) { -+ DEBUG("random_bits pointer cannot be NULL\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ -+ /* loop on generate to get the requested number of bits. Each generate gives NIST_TRNG_RAND_BLK_SIZE_BITS bits. */ -+ req_num_blks = -+ ((req_num_bytes * 8) % NIST_TRNG_RAND_BLK_SIZE_BITS) ? -+ (((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS) + -+ 1) : -+ ((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS); -+ -+ for (i = 0; i < req_num_blks; i++) { -+ /* issue gen_random and wait on done */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_GEN_RANDOM); -+ -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; -+ -+ /* read the generated random number block and store */ -+ for (j = 0; j < (NIST_TRNG_RAND_BLK_SIZE_BITS / 32); j++) { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_RAND0 + j); -+ /* copy to random_bits byte-by-byte, until req_num_bytes are copied */ -+ remained_bytes = req_num_bytes - -+ (i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4); -+ if (remained_bytes > 4) { -+ memcpy(random_bits + -+ i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, 4); -+ -+ /* decrement the bits counter and return error if generated more than the maximum*/ -+ state->counters.bits_per_req_left = -+ state->counters.bits_per_req_left - -+ 4 * 8; -+ -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ flash@2 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "fmc0:2"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; + -+ } else { -+ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, remained_bytes); ++&spi0 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; ++ pinctrl-names = "default"; + -+ /* decrement the bits counter and return error if generated more than the maximum*/ -+ state->counters.bits_per_req_left = -+ state->counters.bits_per_req_left - -+ remained_bytes * 8; ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi0:0"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; + -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ break; -+ } -+ } -+ } ++ flash@1 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "spi0:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_gen_random */ -+EXPORT_SYMBOL(nisttrng_gen_random); ++&spi1 { ++ status = "okay"; ++ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; ++ pinctrl-names = "default"; ++ ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++ label = "spi1:0"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++ ++ flash@1 { ++ status = "disabled"; ++ m25p,fast-read; ++ label = "spi1:1"; ++ spi-max-frequency = <50000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; ++ ++&spi2 { ++ status = "disabled"; ++}; ++ ++&emmc_controller { ++ status = "disabled"; ++}; ++ ++&emmc { ++ status = "disabled"; ++}; ++ ++&ufs_controller { ++ status = "disabled"; ++}; ++ ++&ufs { ++ status = "disabled"; ++}; ++ ++&video0 { ++ status = "disabled"; ++}; ++ ++&video1 { ++ status = "disabled"; ++}; ++ ++&disp_intf { ++ status = "disabled"; ++}; ++ ++#if PCIE0_EP ++&bmc_dev0 { ++ status = "disabled"; ++}; ++ ++&xdma0 { ++ status = "disabled"; ++}; ++ ++&pcie_vuart0 { ++ status = "disabled"; ++}; ++ ++&pcie_vuart1 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc0_kcs0 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc0_kcs1 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc0_kcs2 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc0_kcs3 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc0_ibt { ++ status = "disabled"; ++}; ++ ++&pcie0_mmbi0 { ++ status = "disabled"; ++}; ++#else ++&pcie0 { ++ status = "disabled"; ++}; ++#endif ++ ++#if PCIE1_EP ++&bmc_dev1 { ++ status = "disabled"; ++}; ++ ++&xdma1 { ++ status = "disabled"; ++}; ++ ++&pcie_vuart2 { ++ status = "disabled"; ++}; ++ ++&pcie_vuart3 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc1_kcs0 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc1_kcs1 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc1_kcs2 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc1_kcs3 { ++ status = "disabled"; ++}; ++ ++&pcie_lpc1_ibt { ++ status = "disabled"; ++}; ++ ++&pcie1_mmbi4 { ++ status = "disabled"; ++}; ++#else ++&pcie1 { ++ status = "disabled"; ++}; ++#endif ++ ++&sdio_controller { ++ status = "disabled"; ++}; ++ ++&sdhci { ++ status = "disabled"; ++}; + +diff --git a/crypto/aspeed_crypt.c b/crypto/aspeed_crypt.c +--- a/crypto/aspeed_crypt.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/crypto/aspeed_crypt.c 2026-09-09 15:51:44.713238147 +0000 +@@ -0,0 +1,264 @@ ++// SPDX-License-Identifier: GPL-2.0+ +/* -+ * Generate Part 3 - Advance the state: advances the state of the DRBG. -+ * > This API issues the Advance_State command to the HW. -+ * > Then it updates the counter for the number of generate requests per seed. -+ * > The counter must be checked every time before starting the Generate process and a reseed must be issued if the limit is reached. This check is incorporated inside nisttrng_generate API. -+ * > Note that we don't have to provide additional input again for this API, because if it had been provided in refresh_addin stage, HW will lock the NPA_DATAx, so it will be still available ++ * Copyright 2025 Aspeed Technology Inc. + */ -+int nisttrng_advance_state(struct nist_trng_state *state) ++ ++#define ASPEED_CRYPT_NAME "aspeed-crypt" ++#define pr_fmt(fmt) ASPEED_CRYPT_NAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "internal.h" ++ ++enum aspeed_crypt_type { ++ ASPEED_SKCIPHER_TYPE, ++ ASPEED_AHASH_TYPE, ++ ASPEED_AKCIPHER_TYPE, ++ ASPEED_SIG_TYPE, ++}; ++ ++struct aspeed_crypt_drv { ++ char *algo; ++ char *drv_name; ++}; ++ ++struct aspeed_crypt_test { ++ char *test_item; ++ enum aspeed_crypt_type type; ++ int num; ++ struct aspeed_crypt_drv *algo; ++}; ++ ++struct aspeed_crypt_drv aspeed_des_binding[] = { ++ { "ecb(des)", "aspeed-ecb-des" }, ++ { "cbc(des)", "aspeed-cbc-des" }, ++ { "ctr(des)", "aspeed-ctr-des" }, ++}; ++ ++struct aspeed_crypt_drv aspeed_tdes_binding[] = { ++ { "ecb(des3_ede)", "aspeed-ecb-tdes" }, ++ { "cbc(des3_ede)", "aspeed-cbc-tdes" }, ++ { "ctr(des3_ede)", "aspeed-ctr-tdes" }, ++}; ++ ++struct aspeed_crypt_drv aspeed_sha3_binding[] = { ++ { "sha3-224", "aspeed-sha3-224" }, ++ { "sha3-256", "aspeed-sha3-256" }, ++ { "sha3-384", "aspeed-sha3-384" }, ++ { "sha3-512", "aspeed-sha3-512" }, ++}; ++ ++struct aspeed_crypt_drv aspeed_rsa_binding[] = { ++ { "rsa", "aspeed-rsa" }, ++}; ++ ++struct aspeed_crypt_drv aspeed_ecdsa_binding[] = { ++ { "ecdsa-nist-p256", "aspeed-ecdsa-nist-p256" }, ++ { "ecdsa-nist-p384", "aspeed-ecdsa-nist-p384" }, ++}; ++ ++static bool aspeed_detect_skcipher_drv(char *drv_name) +{ -+ int err; ++ struct crypto_skcipher *tfm = NULL; ++ bool found = false; ++ ++ tfm = crypto_alloc_skcipher(drv_name, 0, 0); ++ if (!IS_ERR(tfm)) { ++ found = true; ++ crypto_free_skcipher(tfm); ++ } + -+ DEBUG(">> %s starts...\n", __func__); ++ return found; ++} ++ ++static bool aspeed_detect_ahash_drv(char *drv_name) ++{ ++ struct crypto_ahash *tfm = NULL; ++ bool found = false; + -+ /* if the DRBG is not intantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ err = CRYPTO_FAILED; -+ goto ERR; ++ tfm = crypto_alloc_ahash(drv_name, 0, 0); ++ if (!IS_ERR(tfm)) { ++ found = true; ++ crypto_free_ahash(tfm); + } + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ return found; ++} + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++static bool aspeed_detect_akcipher_drv(char *drv_name) ++{ ++ struct crypto_akcipher *tfm = NULL; ++ bool found = false; + -+ /* issue advance_state and wait on done */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_ADVANCE_STATE); -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; ++ tfm = crypto_alloc_akcipher(drv_name, 0, 0); ++ if (!IS_ERR(tfm)) { ++ found = true; ++ crypto_free_akcipher(tfm); ++ } + -+ /* generate is finished, reset the bits_per_req_left counter */ -+ state->counters.bits_per_req_left = state->counters.max_bits_per_req; ++ return found; ++} + -+ --state->counters.req_per_seed_left; -+ if (state->counters.req_per_seed_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } /* just a check */ ++static bool aspeed_detect_sig_drv(char *drv_name) ++{ ++ struct crypto_sig *tfm = NULL; ++ bool found = false; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_advance_state */ ++ tfm = crypto_alloc_sig(drv_name, 0, 0); ++ if (!IS_ERR(tfm)) { ++ found = true; ++ crypto_free_sig(tfm); ++ } + -+int nisttrng_check_seed_lifetime(struct nist_trng_state *state) ++ return found; ++} ++ ++static bool aspeed_detect_drv(enum aspeed_crypt_type type, char *drv_name) +{ -+ int err; ++ switch (type) { ++ case ASPEED_SKCIPHER_TYPE: ++ return aspeed_detect_skcipher_drv(drv_name); ++ case ASPEED_AHASH_TYPE: ++ return aspeed_detect_ahash_drv(drv_name); ++ case ASPEED_AKCIPHER_TYPE: ++ return aspeed_detect_akcipher_drv(drv_name); ++ case ASPEED_SIG_TYPE: ++ return aspeed_detect_sig_drv(drv_name); ++ default: ++ return false; ++ } ++} + -+ if (state->counters.req_per_seed_left <= 0) { -+ DEBUG("maximum number of requests per seed is reached\n"); -+ err = CRYPTO_RESEED_REQUIRED; -+ goto ERR; ++static const struct aspeed_crypt_test * ++aspeed_crypt_get_alg(const char *algo_name) ++{ ++ int i = 0; ++ static const struct aspeed_crypt_test algo_ts[] = { ++ { "des", ASPEED_SKCIPHER_TYPE, ARRAY_SIZE(aspeed_des_binding), ++ aspeed_des_binding }, ++ { "des3", ASPEED_SKCIPHER_TYPE, ARRAY_SIZE(aspeed_tdes_binding), ++ aspeed_tdes_binding }, ++ { "sha-3", ASPEED_AHASH_TYPE, ARRAY_SIZE(aspeed_sha3_binding), ++ aspeed_sha3_binding }, ++ { "rsa", ASPEED_AKCIPHER_TYPE, ARRAY_SIZE(aspeed_rsa_binding), ++ aspeed_rsa_binding }, ++ { "ecdsa", ASPEED_SIG_TYPE, ARRAY_SIZE(aspeed_ecdsa_binding), ++ aspeed_ecdsa_binding }, ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(algo_ts); i++) { ++ if (strlen(algo_ts[i].test_item) == strlen(algo_name) && ++ strncmp(algo_ts[i].test_item, algo_name, ++ strlen(algo_name)) == 0) ++ return &algo_ts[i]; + } + -+ err = CRYPTO_OK; -+ERR: -+ return err; ++ return NULL; +} -+EXPORT_SYMBOL(nisttrng_advance_state); + -+/* -+ * Perform Known Answer Test -+ * > The NIST_TRNG can perform a KAT on the DRBG and the derivation function inside the entropy source. There are also two different vectors available to do the KAT. -+ * > The kat_sel input selects whether the KAT should be performed on the DRBG or the derivation function. -+ * > The kat_vec input chooses the KAT vector. -+ * > Selections are done by writing the values to the MODE register. -+ * > If the KAT fails, the API returns error. -+ */ -+int nisttrng_kat(struct nist_trng_state *state, int kat_sel, int kat_vec) ++static __maybe_unused int aspeed_crypt_run_tests(char *alg_name) +{ -+ int err; -+ u32 tmp; ++ const struct aspeed_crypt_test *ts; ++ int ret = 0; ++ int i = 0; + -+ DEBUG(">> %s: kat_sel = %u, kat_vec = %u\n", __func__, -+ kat_sel, kat_vec); ++ ts = aspeed_crypt_get_alg(alg_name); ++ if (!ts) { ++ pr_err("No test suite found for algorithm: %s", alg_name); ++ return -EINVAL; ++ } + -+ /* set KAT_SEL and KAT_VEC */ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); -+ tmp = NIST_TRNG_REG_MODE_SET_KAT_SEL(tmp, kat_sel); -+ tmp = NIST_TRNG_REG_MODE_SET_KAT_VEC(tmp, kat_vec); -+ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++ for (i = 0; i < ts->num && ret == 0; i++) { ++ if (aspeed_detect_drv(ts->type, ts->algo[i].drv_name)) ++ ret = alg_test(ts->algo[i].drv_name, ts->algo[i].algo, ++ 0, 0); ++ else ++ ret = -ENOENT; + -+ /* issue the command and wait on kat_completed */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_KAT); ++ pr_info("alg: %s tests %s\n", ts->algo[i].algo, ++ !ret ? "passed" : "failed"); ++ } + -+ err = nisttrng_wait_on_kat_completed(state); -+ if (err) -+ goto ERR; ++ return ret; ++} + -+ /* check for alarms */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++#if defined(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && \ ++ !defined(CONFIG_CRYPTO_DEV_ASPEED_ACRY) ++static ssize_t aspeed_crypt_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ pr_err("Crypto tests are disabled\n"); ++ return -EOPNOTSUPP; ++} ++#else ++static ssize_t aspeed_crypt_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ u8 kbuf[16] = { 0 }; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_kat */ -+EXPORT_SYMBOL(nisttrng_kat); ++ if (count > sizeof(kbuf) - 1) ++ return -EINVAL; + -+/* -+ * Performs a full KAT with all four combinations of the kat_sel and kat_vec -+ * > If any of the KAT fails, the API returns error. -+ */ -+int nisttrng_full_kat(struct nist_trng_state *state) ++ if (copy_from_user(kbuf, ubuf, min(count, sizeof(kbuf)))) ++ return -EFAULT; ++ strim(kbuf); ++ ++ if (!aspeed_crypt_run_tests(kbuf)) ++ pr_err("alg: %s tests passed\n", kbuf); ++ else ++ pr_err("alg: %s tests failed\n", kbuf); ++ ++ return min(count, sizeof(kbuf)); ++} ++#endif ++ ++static const struct file_operations fops = { ++ .owner = THIS_MODULE, ++ .write = aspeed_crypt_write, ++}; ++ ++static dev_t dev; ++static struct cdev cdev; ++static struct class *class; ++static int __init acrypt_mod_init(void) +{ -+ int err; ++ int ret; + -+ DEBUG(">> %s starts...\n", __func__); ++ ret = alloc_chrdev_region(&dev, 0, 1, ASPEED_CRYPT_NAME); ++ if (ret < 0) ++ return ret; + -+ /* SEL = 0, Vec = 0 */ -+ err = nisttrng_kat(state, 0, 0); -+ if (err) -+ goto ERR; ++ cdev_init(&cdev, &fops); ++ ret = cdev_add(&cdev, dev, 1); ++ if (ret) ++ goto del_region; + -+ /* SEL = 0, Vec = 1 */ -+ err = nisttrng_kat(state, 0, 1); -+ if (err) -+ goto ERR; ++ class = class_create(ASPEED_CRYPT_NAME); ++ if (IS_ERR(class)) { ++ ret = PTR_ERR(class); ++ goto del_cdev; ++ } + -+ /* SEL = 1, Vec = 0 */ -+ err = nisttrng_kat(state, 1, 0); -+ if (err) -+ goto ERR; ++ device_create(class, NULL, dev, NULL, ASPEED_CRYPT_NAME); ++ return 0; ++del_cdev: ++ cdev_del(&cdev); ++del_region: ++ unregister_chrdev_region(dev, 1); ++ return ret; ++} + -+ /* SEL = 1, Vec = 1 */ -+ err = nisttrng_kat(state, 1, 1); -+ if (err) -+ goto ERR; ++static void __exit acrypt_mod_fini(void) ++{ ++ device_destroy(class, dev); ++ class_destroy(class); ++ cdev_del(&cdev); ++ unregister_chrdev_region(dev, 1); ++} + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_full_kat */ -+EXPORT_SYMBOL(nisttrng_full_kat); ++subsys_initcall(acrypt_mod_init); ++module_exit(acrypt_mod_fini); +diff --git a/drivers/bus/aspeed-ltpi.c b/drivers/bus/aspeed-ltpi.c +--- a/drivers/bus/aspeed-ltpi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/bus/aspeed-ltpi.c 2026-09-09 15:51:44.538240791 +0000 +@@ -0,0 +1,1195 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright ASPEED Technology + -+/* -+ * max_bits_per_req reminder initialized by nisttrng_init can change using this API. -+ * > If this API is called when the DRBG is instantiated, an error will be returned. -+ * > If the requested maximum is more than the standard's limit (determinded by NIST_TRNG_DFLT_MAX_BITS_PER_REQ), the API will return an error. -+ */ -+int nisttrng_set_reminder_max_bits_per_req(struct nist_trng_state *state, -+ unsigned long max_bits_per_req) ++#include "linux/dev_printk.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "aspeed-ltpi.h" ++ ++#define LTPI_AUTO_CAP_LOW 0x24 ++#define LTPI_I2C_IO_FRAME_EN GENMASK(29, 24) ++#define LTPI_AUTO_CAP_HIGH 0x28 ++#define LTPI_UART_IO_FRAME_EN GENMASK(14, 13) ++ ++#define LTPI_LINK_CONTROLL 0x80 ++#define LTPI_AUTO_CONFIG BIT(10) ++ ++#define LTPI_INTR_STATUS 0x100 ++#define LTPI_INTR_EN 0x104 ++#define LTPI_INTR_EN_OP_LINK_LOST BIT(4) ++#define LTPI_LINK_MANAGE_ST 0x108 ++#define LTPI_LINK_PARTNER_FLAG BIT(24) ++ ++#define LTPI_MANUAL_CAP_LOW 0x118 ++#define LTPI_MANUAL_CAP_HIGH 0x11c ++ ++#define LTPI_I2C_TIMING_0 0x134 ++#define LTPI_I2C_TIMING_1 0x138 ++ ++#define LTPI_I2C_100K_0 0x3535352f ++#define LTPI_I2C_100K_1 0x09353535 ++ ++#define LTPI_I2C_400K_0 0x06060d06 ++#define LTPI_I2C_400K_1 0x090d0a06 ++ ++#define SCU_IO_PINS_TRAP1 0x10 ++#define SCU_IO_PINS_TRAP1_CLEAR 0x14 ++#define SCU_IO_PINS_TRAP_LTPI GENMASK(2, 0) ++#define SCU_IO_OTP_TRAP1 0xa00 ++#define SCU_IO_OTP_TRAP1_CLEAR 0xa04 ++#define SCU_IO_OTP_TRAP2 0xa20 ++#define SCU_IO_OTP_TRAP2_CLEAR 0xa24 ++ ++/* SCU registers for PLL control */ ++#define SCU1_HPLL_1 0x300 ++#define SCU1_HPLL_2 0x304 ++#define SCU1_APLL_1 0x310 ++#define SCU1_APLL_2 0x314 ++#define SCU1_DPLL_1 0x320 ++#define SCU1_DPLL_2 0x324 ++#define SCU1_L0PLL_1 0x340 ++#define SCU1_L0PLL_2 0x344 ++#define SCU1_L1PLL_1 0x350 ++#define SCU1_L1PLL_2 0x354 ++ ++#define PLL_REG1_RESET BIT(25) ++#define PLL_REG1_BYPASS BIT(24) ++#define PLL_REG1_DIS BIT(23) ++#define PLL_REG1_P GENMASK(22, 19) ++#define PLL_REG1_N GENMASK(18, 13) ++#define PLL_REG1_M GENMASK(12, 0) ++ ++#define PLL_REG2_LOCK BIT(31) ++#define PLL_REG2_BWADJ GENMASK(11, 0) ++ ++#define MAX_I2C_IN_LTPI 6 ++#define MAX_UART_IN_LTPI 2 ++ ++#define ADVERTISE_TIMEOUT_US 105000 /* 105 ms */ ++ ++enum chip_version { ++ AST2700, ++ AST1700, ++}; ++ ++struct ltpi_clk_info { ++ s16 freq; /* clock frequency in MHz*/ ++ s16 clk_sel; /* clock selection */ ++}; ++ ++static const struct ltpi_clk_info ltpi_clk_lookup_sdr[13] = { ++ { 25, REG_LTPI_PLL_25M }, ++ { 50, REG_LTPI_PLL_LPLL }, ++ { 75, REG_LTPI_PLL_LPLL }, ++ { 100, REG_LTPI_PLL_LPLL }, ++ { 150, REG_LTPI_PLL_LPLL }, ++ { 200, REG_LTPI_PLL_LPLL }, ++ { 250, REG_LTPI_PLL_LPLL }, ++ { 300, REG_LTPI_PLL_LPLL }, ++ { 400, REG_LTPI_PLL_LPLL }, ++ { 600, REG_LTPI_PLL_LPLL }, ++ { -1, -1 }, ++ { -1, -1 }, ++ { 500, REG_LTPI_PLL_LPLL } ++}; ++ ++static const struct ltpi_clk_info ltpi_clk_lookup_ddr[13] = { ++ { 50, REG_LTPI_PLL_LPLL }, ++ { 100, REG_LTPI_PLL_LPLL }, ++ { 150, REG_LTPI_PLL_LPLL }, ++ { 200, REG_LTPI_PLL_LPLL }, ++ { 300, REG_LTPI_PLL_LPLL }, ++ { 400, REG_LTPI_PLL_LPLL }, ++ { 500, REG_LTPI_PLL_LPLL }, ++ { 600, REG_LTPI_PLL_LPLL }, ++ { 800, REG_LTPI_PLL_LPLL }, ++ { 1200, REG_LTPI_PLL_LPLL }, ++ { -1, -1 }, ++ { -1, -1 }, ++ { 1000, REG_LTPI_PLL_LPLL } ++}; ++ ++#define MHZ(x) ((x) * 1000000) ++#define NUM_PLL_PARAM 13 ++#define REG_N_M_P(n, m, p) ((((n) - 1) << 13) | ((m) - 1) | (((p) - 1) << 19)) ++#define REG_BWADJ(bwadj) ((bwadj) - 1) ++ ++struct pll_param { ++ int freq; ++ u32 n_m_p; ++ u16 bwadj; ++}; ++ ++static const struct pll_param pll_param_lookup[NUM_PLL_PARAM] = { ++ { .freq = MHZ(50), .n_m_p = REG_N_M_P(1, 32, 16), .bwadj = REG_BWADJ(16) }, ++ { .freq = MHZ(75), .n_m_p = REG_N_M_P(1, 48, 16), .bwadj = REG_BWADJ(24) }, ++ { .freq = MHZ(100), .n_m_p = REG_N_M_P(1, 56, 14), .bwadj = REG_BWADJ(28) }, ++ { .freq = MHZ(150), .n_m_p = REG_N_M_P(1, 60, 10), .bwadj = REG_BWADJ(30) }, ++ { .freq = MHZ(200), .n_m_p = REG_N_M_P(1, 48, 6), .bwadj = REG_BWADJ(24) }, ++ { .freq = MHZ(250), .n_m_p = REG_N_M_P(1, 60, 6), .bwadj = REG_BWADJ(30) }, ++ { .freq = MHZ(300), .n_m_p = REG_N_M_P(1, 48, 4), .bwadj = REG_BWADJ(24) }, ++ { .freq = MHZ(400), .n_m_p = REG_N_M_P(1, 32, 2), .bwadj = REG_BWADJ(16) }, ++ { .freq = MHZ(500), .n_m_p = REG_N_M_P(1, 40, 2), .bwadj = REG_BWADJ(20) }, ++ { .freq = MHZ(600), .n_m_p = REG_N_M_P(1, 48, 2), .bwadj = REG_BWADJ(24) }, ++ { .freq = MHZ(800), .n_m_p = REG_N_M_P(1, 32, 1), .bwadj = REG_BWADJ(16) }, ++ { .freq = MHZ(1000), .n_m_p = REG_N_M_P(1, 40, 1), .bwadj = REG_BWADJ(20) }, ++ { .freq = MHZ(1200), .n_m_p = REG_N_M_P(1, 48, 1), .bwadj = REG_BWADJ(24) }, ++}; ++ ++struct pll_info { ++ u32 reg_offset0; ++ u32 reg_offset1; ++}; ++ ++static const struct pll_info scu_pll_info[] = { ++ [0] = { .reg_offset0 = SCU1_L0PLL_1, .reg_offset1 = SCU1_L0PLL_2 }, ++ [1] = { .reg_offset0 = SCU1_L1PLL_1, .reg_offset1 = SCU1_L1PLL_2 }, ++}; ++ ++struct aspeed_ltpi_priv { ++ struct device *dev; ++ void __iomem *regs; ++ void __iomem *phy_regs; ++ void __iomem *top_regs; ++ struct clk *ltpi_clk; ++ struct clk *ltpi_phyclk; ++ struct reset_control *ltpi_rst; ++ struct regmap *scu; ++ u32 version; ++ u32 i2c_tunneling; ++ u32 i2c_timing_0; ++ u32 i2c_timing_1; ++ u32 uart_tunneling; ++ int index; ++ ++ /* Training parameters */ ++ u16 phy_speed_cap; ++ bool otp_ddr_dis; ++ int disable_auto_downshift; ++ int crc_format; ++ int io_driving; ++ int clk_inverse; ++ int link_speed_frm_rx_cnt; ++ int ad_timeout; ++ u64 op_timeout; ++ u64 t_link_detect; ++}; ++ ++static int ltpi_get_link_partner(struct aspeed_ltpi_priv *ltpi) +{ -+ int err; ++ u32 reg = readl(ltpi->regs + LTPI_LINK_MNG_ST); ++ ++ return FIELD_GET(REG_LTPI_LINK_PARTNER_FLAG, reg); ++} ++ ++static void ltpi_dump(struct aspeed_ltpi_priv *ltpi) ++{ ++ int i; + -+ DEBUG(">> %s: %lu\n", __func__, max_bits_per_req); ++ dev_warn(ltpi->dev, "\nDumping LTPI registers:\n"); ++ for (i = 0; i < 0x250; i += 0x10) { ++ dev_warn(ltpi->dev, "control[%08x]: %08x %08x %08x %08x\n", i, ++ readl(ltpi->regs + i), readl(ltpi->regs + i + 4), ++ readl(ltpi->regs + i + 8), readl(ltpi->regs + i + 12)); ++ } + -+ /* if the DRBG is instantiated, cannot change the value */ -+ if (DRBG_INSTANTIATED(state->status.current_state)) { -+ DEBUG("cannot change the reminder value when DRBG is already instantiated\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; ++ for (i = 0; i < 0x30; i += 0x10) { ++ dev_warn(ltpi->dev, "PHY[%08x]: %08x %08x %08x %08x\n", i, ++ readl(ltpi->phy_regs + i), ++ readl(ltpi->phy_regs + i + 4), ++ readl(ltpi->phy_regs + i + 8), ++ readl(ltpi->phy_regs + i + 12)); + } ++} + -+ /* requested value cannot be more than NIST's limit */ -+ if (max_bits_per_req > NIST_DFLT_MAX_BITS_PER_REQ) { -+ DEBUG("requested max_bits_per_req is more than standard's limit\n"); -+ err = CRYPTO_INVALID_ARGUMENT; -+ goto ERR; ++static irqreturn_t aspeed_ltpi_irq_handler(int irq, void *dev_id) ++{ ++ struct aspeed_ltpi_priv *priv = dev_id; ++ u32 status = readl(priv->regs + LTPI_INTR_STATUS); ++ ++ if (status & LTPI_INTR_EN_OP_LINK_LOST) { ++ writel(0, priv->regs + LTPI_INTR_EN); ++ writel(status, priv->regs + LTPI_INTR_STATUS); ++ if (ltpi_get_link_partner(priv)) ++ panic("LTPI link lost!\n"); ++ /* Will not return */ ++ else ++ dev_err(priv->dev, "LTPI link lost!\n"); + } + -+ state->counters.max_bits_per_req = max_bits_per_req; -+ state->counters.bits_per_req_left = max_bits_per_req; ++ writel(status, priv->regs + LTPI_INTR_STATUS); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++ return IRQ_HANDLED; +} -+EXPORT_SYMBOL(nisttrng_set_reminder_max_bits_per_req); + -+/* -+ * max_req_per_seed reminder initialized by nisttrng_init can change using this API. -+ * > If this API is called when the DRBG is instantiated, an error will be returned. -+ * > If the requested maximum is more than the standard's limit (determinded by NIST_TRNG_DFLT_MAX_REQ_PER_SEED), the API will return an error. -+ */ -+int nisttrng_set_reminder_max_req_per_seed(struct nist_trng_state *state, -+ unsigned long long max_req_per_seed) ++static int aspeed_ltpi_init_mux(struct aspeed_ltpi_priv *priv) +{ -+ int err; ++ u32 reg, i2c_en, uart_en, i; ++ ++ reg = readl(priv->regs + LTPI_AUTO_CAP_LOW); ++ ++ i2c_en = FIELD_GET(LTPI_I2C_IO_FRAME_EN, reg); ++ i2c_en &= priv->i2c_tunneling; ++ ++ reg &= ~LTPI_I2C_IO_FRAME_EN; ++ reg |= FIELD_PREP(LTPI_I2C_IO_FRAME_EN, i2c_en); ++ writel(reg, priv->regs + LTPI_MANUAL_CAP_LOW); ++ ++ reg = readl(priv->regs + LTPI_AUTO_CAP_HIGH); ++ ++ uart_en = FIELD_GET(LTPI_UART_IO_FRAME_EN, reg); ++ uart_en &= priv->uart_tunneling; + -+ DEBUG(">> %s: %llu\n", __func__, max_req_per_seed); ++ reg &= ~LTPI_UART_IO_FRAME_EN; ++ reg |= FIELD_PREP(LTPI_UART_IO_FRAME_EN, uart_en); ++ ++ writel(reg, priv->regs + LTPI_MANUAL_CAP_HIGH); ++ ++ /* Apply LTPI manual configuration */ ++ reg = readl(priv->regs + LTPI_LINK_CONTROLL); ++ reg &= ~LTPI_AUTO_CONFIG; ++ writel(reg, priv->regs + LTPI_LINK_CONTROLL); + -+ /* if the DRBG is instantiated, cannot change the value */ -+ if (DRBG_INSTANTIATED(state->status.current_state)) { -+ DEBUG("cannot change the reminder value when DRBG is already instantiated\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; ++ /* Set the AST1700 i2c ac-timing */ ++ if (priv->version == AST1700) { ++ /* Apply i2c timing with i2c tunneling setting */ ++ for (i = 0; i < MAX_I2C_IN_LTPI; i++) { ++ if ((priv->i2c_tunneling >> i) & 0x1) { ++ writel(priv->i2c_timing_0, ++ priv->regs + LTPI_I2C_TIMING_0 + ++ (0x8 * i)); ++ writel(priv->i2c_timing_1, ++ priv->regs + LTPI_I2C_TIMING_1 + ++ (0x8 * i)); ++ } ++ } + } + -+ /* requested value cannot be more than NIST's limit */ -+ if (max_req_per_seed > NIST_DFLT_MAX_REQ_PER_SEED) { -+ DEBUG("requested max_req_per_seed is more than standard's limit\n"); -+ err = CRYPTO_INVALID_ARGUMENT; -+ goto ERR; ++ return 0; ++} ++ ++static int clz16(u16 x) ++{ ++ int n = 0; ++ ++ if (x == 0) ++ return 16; ++ ++ if (x <= 0x00ff) { ++ n += 8; ++ x <<= 8; + } ++ if (x <= 0x0fff) { ++ n += 4; ++ x <<= 4; ++ } ++ if (x <= 0x3fff) { ++ n += 2; ++ x <<= 2; ++ } ++ if (x <= 0x7fff) ++ n += 1; + -+ state->counters.max_req_per_seed = max_req_per_seed; -+ state->counters.req_per_seed_left = max_req_per_seed; ++ return n; ++} + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++static u16 find_max_speed(u16 cap) ++{ ++ return 15 - clz16(cap & ~LTPI_SP_CAP_DDR); +} -+EXPORT_SYMBOL(nisttrng_set_reminder_max_req_per_seed); + -+/* -+ * Zeroize command -+ * > A zeroize will not destroy the programmed mode and ALARM register value. -+ * It keeps the programmed mode to avoid re-programming. -+ * It also, maintains the ALARM register value, so that the user can read the value to understand the reason of the occurred alarm. -+ */ -+int nisttrng_zeroize(struct nist_trng_state *state) ++static void ltpi_phy_unlock(struct aspeed_ltpi_priv *ltpi) +{ -+ int err; ++ writel(LTPI_PROT_KEY_UNLOCK, ltpi->phy_regs + LTPI_PROT_KEY); ++} + -+ DEBUG(">> %s: zeroize the core\n", __func__); ++static void ltpi_enable_rx_bias(struct aspeed_ltpi_priv *ltpi) ++{ ++ u32 val = readl(ltpi->top_regs + LTPI_LVDS_RX_CTRL); + -+ /* issue zeroize command */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_ZEROIZE); ++ val |= (REG_LTPI_LVDS_RX1_BIAS_EN | REG_LTPI_LVDS_RX0_BIAS_EN); ++ writel(val, ltpi->top_regs + LTPI_LVDS_RX_CTRL); ++ udelay(1); ++} + -+ /* wait on zeroize done */ -+ err = nisttrng_wait_on_zeroize(state); -+ if (err) -+ goto ERR; ++static int ltpi_phy_get_mode(struct aspeed_ltpi_priv *ltpi) ++{ ++ u32 reg = readl(ltpi->phy_regs + LTPI_PHY_CTRL); + -+ /* reset the SW state */ -+ nisttrng_reset_state(state); ++ return FIELD_GET(REG_LTPI_PHY_MODE, reg); ++} + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_UNINSTANTIATE; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_zeroize */ -+EXPORT_SYMBOL(nisttrng_zeroize); ++static int ltpi_phy_set_mode(struct aspeed_ltpi_priv *ltpi, int mode) ++{ ++ u32 reg; ++ ++ if (mode < 0 || mode > LTPI_PHY_MODE_CDR_HI_SP) { ++ dev_err(ltpi->dev, "%s: invalid mode %d\n", __func__, mode); ++ return -1; ++ } ++ ++ reg = readl(ltpi->phy_regs + LTPI_PHY_CTRL); ++ reg &= ~REG_LTPI_PHY_MODE; ++ reg |= mode; ++ writel(reg, ltpi->phy_regs + LTPI_PHY_CTRL); ++ ++ return 0; ++} + -+int nisttrng_rnc(struct nist_trng_state *state, int rnc_ctrl_cmd) ++static int ltpi_phy_set_clksel(struct aspeed_ltpi_priv *ltpi, int clksel, ++ bool is_op_clk) +{ -+ int err = 0; -+ u32 tmp; ++ u32 reg; + -+ DEBUG(">> %s cmd %d\n", __func__, rnc_ctrl_cmd); ++#define RX_CLK_INVERSE BIT(1) ++#define TX_CLK_INVERSE BIT(0) + -+ if (rnc_ctrl_cmd > NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE) { -+ DEBUG(">> Invalid cmd %d\n", rnc_ctrl_cmd); -+ err = -1; -+ goto ERR; -+ } ++ reg = readl(ltpi->phy_regs + LTPI_PLL_CTRL); ++ reg &= ~(REG_LTPI_PLL_SELECT | REG_LTPI_PLL_SET | ++ REG_LTPI_RX_PHY_CLK_INV | REG_LTPI_TX_PHY_CLK_INV); ++ reg |= FIELD_PREP(REG_LTPI_PLL_SELECT, clksel); + -+ if (!state->config.build_cfg0.edu_present) { -+ DEBUG(">> edu not present\n"); -+ err = -1; -+ goto ERR; -+ } ++ if (ltpi->clk_inverse & RX_CLK_INVERSE) ++ reg |= REG_LTPI_RX_PHY_CLK_INV; + -+ pdu_io_write32(state->base + NIST_TRNG_EDU_RNC_CTRL, rnc_ctrl_cmd); -+ if (rnc_ctrl_cmd == NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE) { -+ // wait till rnc is enabled -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); -+ } while (!NIST_TRNG_EDU_STAT_RNC_ENABLED(tmp)); ++ if (ltpi->clk_inverse & TX_CLK_INVERSE) ++ reg |= REG_LTPI_TX_PHY_CLK_INV; + -+ state->status.edu_vstat.rnc_enabled = 1; ++ if (is_op_clk) ++ reg |= REG_LTPI_PLL_SET; + -+ } else { -+ // wait till rnc is idle (disabled) -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); -+ } while (NIST_TRNG_EDU_STAT_RNC_ENABLED(tmp)); ++ writel(reg, ltpi->phy_regs + LTPI_PLL_CTRL); + -+ state->status.edu_vstat.rnc_enabled = 0; -+ } -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++ return 0; +} -+EXPORT_SYMBOL(nisttrng_rnc); + -+int nisttrng_wait_fifo_full(struct nist_trng_state *state) ++static void ltpi_set_crc_format(struct aspeed_ltpi_priv *ltpi, int crc_fmt) +{ -+ int err = 0; -+ u32 tmp, t; ++ u32 val = readl(ltpi->regs + LTPI_CRC_OPTION); + -+ t = NIST_TRNG_RETRY_MAX; ++ val &= ~(REG_LTPI_SW_CRC_OUT_ML_FIRST | REG_LTPI_SW_CRC_IN_LSB_FIRST); ++ if (crc_fmt) ++ val |= REG_LTPI_SW_CRC_OUT_ML_FIRST | ++ REG_LTPI_SW_CRC_IN_LSB_FIRST; + -+ DEBUG(">> %s starts...\n", __func__); ++ writel(val, ltpi->regs + LTPI_CRC_OPTION); ++} + -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); -+ } while ((!NIST_TRNG_EDU_STAT_FIFO_FULL(tmp)) && --t); ++static int ltpi_reset(struct aspeed_ltpi_priv *ltpi) ++{ ++ /* Using reset controller */ ++ reset_control_assert(ltpi->ltpi_rst); ++ udelay(1); ++ /* Assuming clk gate is handled by clock framework or enabled */ ++ /* U-Boot does ungate here */ ++ if (ltpi->ltpi_clk) ++ clk_prepare_enable(ltpi->ltpi_clk); + -+ if (t) { -+ err = CRYPTO_OK; -+ } else { -+ DEBUG("wait_on_fifo_full: failed timeout: %08lx\n", -+ (unsigned long)tmp); -+ err = CRYPTO_TIMEOUT; -+ goto ERR; -+ } ++ reset_control_deassert(ltpi->ltpi_rst); + -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++ ltpi_phy_unlock(ltpi); ++ ++ return 0; +} -diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c ---- a/drivers/char/ipmi/kcs_bmc_aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c 2025-12-23 10:16:21.105032988 +0000 -@@ -1,13 +1,14 @@ - // SPDX-License-Identifier: GPL-2.0 - /* - * Copyright (c) 2015-2018, Intel Corporation. -+ * Copyright (c) 2023, Aspeed Technology Inc. - */ -- - #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt - - #include - #include - #include -+#include - #include - #include - #include -@@ -23,10 +24,9 @@ - - #include "kcs_bmc_device.h" - -+#define DEVICE_NAME "aspeed-kcs-bmc" - --#define DEVICE_NAME "ast-kcs-bmc" -- --#define KCS_CHANNEL_MAX 4 -+static DEFINE_IDA(aspeed_kcs_bmc_ida); - - /* - * Field class descriptions -@@ -38,87 +38,74 @@ - * SELyIRQX SerIRQ polarity for LPC channel y (low: 0, high: 1) - * IRQXEy Assert the SerIRQ specified in IDyIRQX for LPC channel y - */ -- --#define LPC_TYIRQX_LOW 0b00 --#define LPC_TYIRQX_HIGH 0b01 --#define LPC_TYIRQX_RSVD 0b10 --#define LPC_TYIRQX_RISING 0b11 -- --#define LPC_HICR0 0x000 --#define LPC_HICR0_LPC3E BIT(7) --#define LPC_HICR0_LPC2E BIT(6) --#define LPC_HICR0_LPC1E BIT(5) --#define LPC_HICR2 0x008 --#define LPC_HICR2_IBFIE3 BIT(3) --#define LPC_HICR2_IBFIE2 BIT(2) --#define LPC_HICR2_IBFIE1 BIT(1) --#define LPC_HICR4 0x010 --#define LPC_HICR4_LADR12AS BIT(7) --#define LPC_HICR4_KCSENBL BIT(2) --#define LPC_SIRQCR0 0x070 -+#define HICR0 0x000 -+#define HICR0_LPC3E BIT(7) -+#define HICR0_LPC2E BIT(6) -+#define HICR0_LPC1E BIT(5) -+#define HICR2 0x008 -+#define HICR2_IBFIE3 BIT(3) -+#define HICR2_IBFIE2 BIT(2) -+#define HICR2_IBFIE1 BIT(1) -+#define HICR4 0x010 -+#define HICR4_LADR12AS BIT(7) -+#define HICR4_KCSENBL BIT(2) -+#define LADR3H 0x014 -+#define LADR3L 0x018 -+#define LADR12H 0x01C -+#define LADR12L 0x020 -+#define IDR1 0x024 -+#define IDR2 0x028 -+#define IDR3 0x02C -+#define ODR1 0x030 -+#define ODR2 0x034 -+#define ODR3 0x038 -+#define STR1 0x03C -+#define STR2 0x040 -+#define STR3 0x044 -+#define SIRQCR0 0x070 - /* IRQ{12,1}E1 are deprecated as of AST2600 A3 but necessary for prior chips */ --#define LPC_SIRQCR0_IRQ12E1 BIT(1) --#define LPC_SIRQCR0_IRQ1E1 BIT(0) --#define LPC_HICR5 0x080 --#define LPC_HICR5_ID3IRQX_MASK GENMASK(23, 20) --#define LPC_HICR5_ID3IRQX_SHIFT 20 --#define LPC_HICR5_ID2IRQX_MASK GENMASK(19, 16) --#define LPC_HICR5_ID2IRQX_SHIFT 16 --#define LPC_HICR5_SEL3IRQX BIT(15) --#define LPC_HICR5_IRQXE3 BIT(14) --#define LPC_HICR5_SEL2IRQX BIT(13) --#define LPC_HICR5_IRQXE2 BIT(12) --#define LPC_LADR3H 0x014 --#define LPC_LADR3L 0x018 --#define LPC_LADR12H 0x01C --#define LPC_LADR12L 0x020 --#define LPC_IDR1 0x024 --#define LPC_IDR2 0x028 --#define LPC_IDR3 0x02C --#define LPC_ODR1 0x030 --#define LPC_ODR2 0x034 --#define LPC_ODR3 0x038 --#define LPC_STR1 0x03C --#define LPC_STR2 0x040 --#define LPC_STR3 0x044 --#define LPC_HICRB 0x100 --#define LPC_HICRB_EN16LADR2 BIT(5) --#define LPC_HICRB_EN16LADR1 BIT(4) --#define LPC_HICRB_IBFIE4 BIT(1) --#define LPC_HICRB_LPC4E BIT(0) --#define LPC_HICRC 0x104 --#define LPC_HICRC_ID4IRQX_MASK GENMASK(7, 4) --#define LPC_HICRC_ID4IRQX_SHIFT 4 --#define LPC_HICRC_TY4IRQX_MASK GENMASK(3, 2) --#define LPC_HICRC_TY4IRQX_SHIFT 2 --#define LPC_HICRC_OBF4_AUTO_CLR BIT(1) --#define LPC_HICRC_IRQXE4 BIT(0) --#define LPC_LADR4 0x110 --#define LPC_IDR4 0x114 --#define LPC_ODR4 0x118 --#define LPC_STR4 0x11C --#define LPC_LSADR12 0x120 --#define LPC_LSADR12_LSADR2_MASK GENMASK(31, 16) --#define LPC_LSADR12_LSADR2_SHIFT 16 --#define LPC_LSADR12_LSADR1_MASK GENMASK(15, 0) --#define LPC_LSADR12_LSADR1_SHIFT 0 -- --#define OBE_POLL_PERIOD (HZ / 2) -- --enum aspeed_kcs_irq_mode { -- aspeed_kcs_irq_none, -- aspeed_kcs_irq_serirq, --}; -+#define SIRQCR0_IRQ12E1 BIT(1) -+#define SIRQCR0_IRQ1E1 BIT(0) -+#define HICR5 0x080 -+#define HICR5_ID3IRQX GENMASK(23, 20) -+#define HICR5_ID2IRQX GENMASK(19, 16) -+#define HICR5_SEL3IRQX BIT(15) -+#define HICR5_IRQXE3 BIT(14) -+#define HICR5_SEL2IRQX BIT(13) -+#define HICR5_IRQXE2 BIT(12) -+#define HICRB 0x100 -+#define HICRB_EN16LADR2 BIT(5) -+#define HICRB_EN16LADR1 BIT(4) -+#define HICRB_IBFIE4 BIT(1) -+#define HICRB_LPC4E BIT(0) -+#define HICRC 0x104 -+#define HICRC_ID4IRQX GENMASK(7, 4) -+#define HICRC_SEL4IRQX BIT(2) -+#define HICRC_OBF4_AUTO_CLR BIT(1) -+#define HICRC_IRQXE4 BIT(0) -+#define LADR4 0x110 -+#define IDR4 0x114 -+#define ODR4 0x118 -+#define STR4 0x11C -+#define LSADR12 0x120 -+#define LSADR12_LSADR2 GENMASK(31, 16) -+#define LSADR12_LSADR1 GENMASK(15, 0) + -+#define KCS_HW_INSTANCE_NUM 4 -+#define KCS_OBE_POLL_PERIOD (HZ / 2) - - struct aspeed_kcs_bmc { - struct kcs_bmc_device kcs_bmc; -- - struct regmap *map; -+ int irq; ++static u32 ltpi_get_link_mng_state(struct aspeed_ltpi_priv *ltpi) ++{ ++ return FIELD_GET(REG_LTPI_LINK_MNG_ST, ++ readl(ltpi->regs + LTPI_LINK_MNG_ST)); ++} + -+ u32 io_addr; -+ u32 hw_inst; - - struct { -- enum aspeed_kcs_irq_mode mode; -- int id; -- } upstream_irq; -+ u32 id; -+ u32 type; -+ } sirq; - - struct { - spinlock_t lock; -@@ -127,6 +114,13 @@ - } obe; - }; - -+static const struct kcs_ioreg aspeed_kcs_ioregs[KCS_HW_INSTANCE_NUM] = { -+ { .idr = IDR1, .odr = ODR1, .str = STR1 }, -+ { .idr = IDR2, .odr = ODR2, .str = STR2 }, -+ { .idr = IDR3, .odr = ODR3, .str = STR3 }, -+ { .idr = IDR4, .odr = ODR4, .str = STR4 }, -+}; ++static int ltpi_poll_link_mng_state(struct aspeed_ltpi_priv *ltpi, ++ u32 expected, u32 unexpected, ++ int timeout_us) ++{ ++ u32 state; ++ int ret; + - static inline struct aspeed_kcs_bmc *to_aspeed_kcs_bmc(struct kcs_bmc_device *kcs_bmc) - { - return container_of(kcs_bmc, struct aspeed_kcs_bmc, kcs_bmc); -@@ -134,11 +128,11 @@ - - static u8 aspeed_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg) - { -- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); -+ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); - u32 val = 0; - int rc; - -- rc = regmap_read(priv->map, reg, &val); -+ rc = regmap_read(kcs_aspeed->map, reg, &val); - WARN(rc != 0, "regmap_read() failed: %d\n", rc); - - return rc == 0 ? (u8) val : 0; -@@ -146,50 +140,50 @@ - - static void aspeed_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data) - { -- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); -+ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); - int rc; - -- rc = regmap_write(priv->map, reg, data); -+ rc = regmap_write(kcs_aspeed->map, reg, data); - WARN(rc != 0, "regmap_write() failed: %d\n", rc); - - /* Trigger the upstream IRQ on ODR writes, if enabled */ - - switch (reg) { -- case LPC_ODR1: -- case LPC_ODR2: -- case LPC_ODR3: -- case LPC_ODR4: -+ case ODR1: -+ case ODR2: -+ case ODR3: -+ case ODR4: - break; - default: - return; - } - -- if (priv->upstream_irq.mode != aspeed_kcs_irq_serirq) -+ if (kcs_aspeed->sirq.type == IRQ_TYPE_NONE) - return; - -- switch (kcs_bmc->channel) { -- case 1: -- switch (priv->upstream_irq.id) { -+ switch (kcs_aspeed->hw_inst) { -+ case 0: -+ switch (kcs_aspeed->sirq.id) { - case 12: -- regmap_update_bits(priv->map, LPC_SIRQCR0, LPC_SIRQCR0_IRQ12E1, -- LPC_SIRQCR0_IRQ12E1); -+ regmap_update_bits(kcs_aspeed->map, SIRQCR0, SIRQCR0_IRQ12E1, -+ SIRQCR0_IRQ12E1); - break; - case 1: -- regmap_update_bits(priv->map, LPC_SIRQCR0, LPC_SIRQCR0_IRQ1E1, -- LPC_SIRQCR0_IRQ1E1); -+ regmap_update_bits(kcs_aspeed->map, SIRQCR0, SIRQCR0_IRQ1E1, -+ SIRQCR0_IRQ1E1); - break; - default: - break; - } - break; -+ case 1: -+ regmap_update_bits(kcs_aspeed->map, HICR5, HICR5_IRQXE2, HICR5_IRQXE2); -+ break; - case 2: -- regmap_update_bits(priv->map, LPC_HICR5, LPC_HICR5_IRQXE2, LPC_HICR5_IRQXE2); -+ regmap_update_bits(kcs_aspeed->map, HICR5, HICR5_IRQXE3, HICR5_IRQXE3); - break; - case 3: -- regmap_update_bits(priv->map, LPC_HICR5, LPC_HICR5_IRQXE3, LPC_HICR5_IRQXE3); -- break; -- case 4: -- regmap_update_bits(priv->map, LPC_HICRC, LPC_HICRC_IRQXE4, LPC_HICRC_IRQXE4); -+ regmap_update_bits(kcs_aspeed->map, HICRC, HICRC_IRQXE4, HICRC_IRQXE4); - break; - default: - break; -@@ -198,86 +192,116 @@ - - static void aspeed_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 val) - { -- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); -+ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); - int rc; - -- rc = regmap_update_bits(priv->map, reg, mask, val); -+ rc = regmap_update_bits(kcs_aspeed->map, reg, mask, val); - WARN(rc != 0, "regmap_update_bits() failed: %d\n", rc); - } - -+static void aspeed_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state) ++ ret = readl_poll_timeout(ltpi->regs + LTPI_LINK_MNG_ST, state, ++ (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == expected) || ++ (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == unexpected), ++ 100, timeout_us); ++ ++ if (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == unexpected) ++ return -ENOLINK; ++ ++ if (ret) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++static int ltpi_wait_state_pll_set(struct aspeed_ltpi_priv *ltpi, ++ int timeout_us) +{ -+ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); -+ int rc; -+ u8 str; ++ return ltpi_poll_link_mng_state(ltpi, LTPI_LINK_MNG_ST_WAIT_PLL_SET, -1, ++ timeout_us); ++} + -+ /* We don't have an OBE IRQ, emulate it */ -+ if (mask & KCS_BMC_EVENT_TYPE_OBE) { -+ if (KCS_BMC_EVENT_TYPE_OBE & state) { -+ /* -+ * Given we don't have an OBE IRQ, delay by polling briefly to see if we can -+ * observe such an event before returning to the caller. This is not -+ * incorrect because OBF may have already become clear before enabling the -+ * IRQ if we had one, under which circumstance no event will be propagated -+ * anyway. -+ * -+ * The onus is on the client to perform a race-free check that it hasn't -+ * missed the event. -+ */ -+ rc = read_poll_timeout_atomic(aspeed_kcs_inb, str, -+ !(str & KCS_BMC_STR_OBF), 1, 100, false, -+ &kcs_aspeed->kcs_bmc, kcs_aspeed->kcs_bmc.ioreg.str); -+ /* Time for the slow path? */ -+ if (rc == -ETIMEDOUT) -+ mod_timer(&kcs_aspeed->obe.timer, jiffies + KCS_OBE_POLL_PERIOD); -+ } else { -+ del_timer(&kcs_aspeed->obe.timer); ++static int ltpi_wait_state_op(struct aspeed_ltpi_priv *ltpi) ++{ ++ u32 val = readl(ltpi->regs + LTPI_LINK_ST); ++ ++ val |= (REG_LTPI_CON_ACC_TO_ERR | REG_LTPI_FRM_CRC_ERR | ++ REG_LTPI_LINK_LOST_ERR); ++ writel(val, ltpi->regs + LTPI_LINK_ST); ++ ++ return ltpi_poll_link_mng_state(ltpi, LTPI_LINK_MNG_ST_OP, ++ LTPI_LINK_MNG_ST_DETECT_ALIGN, ++ ltpi->ad_timeout); ++} ++ ++static int ltpi_set_lvds_io_driving(struct aspeed_ltpi_priv *ltpi, int driving) ++{ ++ u32 val; ++ ++ val = readl(ltpi->top_regs + LTPI_SW_FORCE_EN); ++ val |= REG_LTPI_SW_FORCE_LVDS_TX_DS_EN; ++ writel(val, ltpi->top_regs + LTPI_SW_FORCE_EN); ++ ++ val = readl(ltpi->top_regs + LTPI_LVDS_TX_CTRL); ++ val &= ~(REG_LTPI_LVDS_TX1_DS1 | REG_LTPI_LVDS_TX1_DS0 | ++ REG_LTPI_LVDS_TX0_DS1 | REG_LTPI_LVDS_TX0_DS0); ++ ++ /* tx1: clk, tx0: data */ ++ if (driving & BIT(1)) ++ val |= (REG_LTPI_LVDS_TX1_DS1 | REG_LTPI_LVDS_TX0_DS1); ++ ++ if (driving & BIT(0)) ++ val |= (REG_LTPI_LVDS_TX1_DS0 | REG_LTPI_LVDS_TX0_DS0); ++ ++ writel(val, ltpi->top_regs + LTPI_LVDS_TX_CTRL); ++ ++ return 0; ++} ++ ++static int ltpi_set_local_speed_cap(struct aspeed_ltpi_priv *ltpi, ++ u32 speed_cap) ++{ ++ u32 reg; ++ ++ /* only set bits that Aspeed SOC supported */ ++ speed_cap &= LTPI_SP_CAP_ASPEED_SUPPORTED; ++ if (ltpi->otp_ddr_dis) ++ speed_cap &= ~LTPI_SP_CAP_DDR; ++ ++ reg = readl(ltpi->regs + LTPI_CAP_LOCAL); ++ reg &= ~REG_LTPI_SP_CAP_LOCAL; ++ reg |= FIELD_PREP(REG_LTPI_SP_CAP_LOCAL, speed_cap); ++ writel(reg, ltpi->regs + LTPI_CAP_LOCAL); ++ ++ return 0; ++} ++ ++static void ltpi_do_link_training(struct aspeed_ltpi_priv *ltpi) ++{ ++ u32 val; ++ ++ /* Reset the PHY to PHY_MODE_OFF */ ++ ltpi_reset(ltpi); ++ ++ ltpi_enable_rx_bias(ltpi); ++ ltpi_set_local_speed_cap(ltpi, ltpi->phy_speed_cap); ++ ltpi_set_lvds_io_driving(ltpi, ltpi->io_driving); ++ ltpi_set_crc_format(ltpi, ltpi->crc_format); ++ ++ /* ++ * Configure the LINK_SPEED frame count to be received before ++ * entering AD. This configuraiton only effects the SCM LTPI. ++ */ ++ val = readl(ltpi->regs + LTPI_LINK_MANAGE_CTRL0); ++ val &= ~REG_LTPI_RX_LINK_SP_FRM_NUM; ++ val |= FIELD_PREP(REG_LTPI_RX_LINK_SP_FRM_NUM, ++ ltpi->link_speed_frm_rx_cnt); ++ writel(val, ltpi->regs + LTPI_LINK_MANAGE_CTRL0); ++ ++ /* ++ * ad_timeout in us = ad_timeout in clock cycles * period of 25MHz ++ * ad_timeout in clock cycles ++ * = ad_timeout in us / period of 25MHz ++ * = (ad_timeout in us * 1000)ns / 40ns = ad_timeout * 25 ++ */ ++ writel(ltpi->ad_timeout * 25, ltpi->regs + LTPI_LINK_MANAGE_CTRL1); ++ ++ /* Set the clock source to the base frequency 25MHz */ ++ ltpi_phy_set_clksel(ltpi, REG_LTPI_PLL_25M, false); ++ ++ /* To make the remote side back to the link lost state */ ++ mdelay(ADVERTISE_TIMEOUT_US / 1000); ++ ++ ltpi_phy_set_mode(ltpi, LTPI_PHY_MODE_SDR); ++} ++ ++static int scu_get_pll_freq(struct aspeed_ltpi_priv *ltpi, int pll_id) ++{ ++ const struct pll_info *info; ++ u32 reg; ++ int m, n, p; ++ ++ if (pll_id > 1) ++ return -1; ++ ++ info = &scu_pll_info[pll_id]; ++ regmap_read(ltpi->scu, info->reg_offset0, ®); ++ m = FIELD_GET(PLL_REG1_M, reg); ++ n = FIELD_GET(PLL_REG1_N, reg); ++ p = FIELD_GET(PLL_REG1_P, reg); ++ ++ return (25000000 * (m + 1) / (n + 1) / (p + 1)); ++} ++ ++static int scu_set_pll_freq(struct aspeed_ltpi_priv *ltpi, int pll_id, int freq) ++{ ++ const struct pll_info *info; ++ const struct pll_param *param; ++ int curr_freq, i; ++ bool match = false; ++ ++ if (pll_id > 1) ++ return -EINVAL; ++ ++ curr_freq = scu_get_pll_freq(ltpi, pll_id); ++ if (curr_freq == freq) ++ return 0; ++ ++ for (i = 0; i < NUM_PLL_PARAM; i++) { ++ if (freq == pll_param_lookup[i].freq) { ++ match = true; ++ break; + } + } + -+ if (mask & KCS_BMC_EVENT_TYPE_IBF) { -+ const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF); ++ if (!match) ++ return -EINVAL; + -+ switch (kcs_aspeed->hw_inst) { -+ case 0: -+ regmap_update_bits(kcs_aspeed->map, HICR2, HICR2_IBFIE1, -+ enable * HICR2_IBFIE1); -+ return; -+ case 1: -+ regmap_update_bits(kcs_aspeed->map, HICR2, HICR2_IBFIE2, -+ enable * HICR2_IBFIE2); -+ return; -+ case 2: -+ regmap_update_bits(kcs_aspeed->map, HICR2, HICR2_IBFIE3, -+ enable * HICR2_IBFIE3); -+ return; -+ case 3: -+ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_IBFIE4, -+ enable * HICRB_IBFIE4); -+ return; -+ default: -+ pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel); -+ return; ++ param = &pll_param_lookup[i]; ++ info = &scu_pll_info[pll_id]; ++ ++ dev_info(ltpi->dev, "Setting PLL frequency to %d MHz\n", ++ freq / 1000000); ++ regmap_update_bits(ltpi->scu, info->reg_offset0, PLL_REG1_RESET, ++ PLL_REG1_RESET); ++ regmap_update_bits(ltpi->scu, info->reg_offset0, ++ PLL_REG1_P | PLL_REG1_N | PLL_REG1_M, param->n_m_p); ++ regmap_update_bits(ltpi->scu, info->reg_offset1, PLL_REG2_BWADJ, ++ param->bwadj); ++ ++ udelay(5); ++ regmap_update_bits(ltpi->scu, info->reg_offset0, PLL_REG1_RESET, 0); ++ udelay(20); ++ ++ return 0; ++} ++ ++static int ltpi_set_operational_clk(struct aspeed_ltpi_priv *ltpi, ++ u16 speed_cap) ++{ ++ const struct ltpi_clk_info *info; ++ int target_speed, clksel, phy_mode, pll_id; ++ ++ pll_id = ltpi->index; /* 0 or 1 maps to L0PLL or L1PLL in array */ ++ ++ /* find max attainable speed */ ++ target_speed = find_max_speed(speed_cap); ++ ++ /* set phy mode "OFF" */ ++ ltpi_phy_set_mode(ltpi, LTPI_PHY_MODE_OFF); ++ ++ if (speed_cap & LTPI_SP_CAP_DDR) { ++ phy_mode = LTPI_PHY_MODE_DDR; ++ info = ltpi_clk_lookup_ddr; ++ } else { ++ phy_mode = LTPI_PHY_MODE_SDR; ++ info = ltpi_clk_lookup_sdr; ++ } ++ clksel = info[target_speed].clk_sel; ++ ltpi_phy_set_clksel(ltpi, clksel, true); ++ if (clksel == REG_LTPI_PLL_LPLL) ++ scu_set_pll_freq(ltpi, pll_id, ++ info[target_speed].freq * 1000000); ++ ++ /* Start TX with the operational frequency */ ++ ltpi_phy_set_mode(ltpi, phy_mode); ++ ++ return target_speed; ++} ++ ++static int ltpi_scm_init(struct aspeed_ltpi_priv *ltpi) ++{ ++ int ret, target_speed; ++ u32 reg, state; ++ ++ dev_info(ltpi->dev, "Starting LTPI initialization\n"); ++ /* Check whether LTPI is initialized */ ++ state = ltpi_get_link_mng_state(ltpi); ++ if (state == LTPI_LINK_MNG_ST_OP) { ++ dev_info(ltpi->dev, "LTPI already operational PHY mode: %d\n", ++ ltpi_phy_get_mode(ltpi)); ++ return 0; ++ } ++ ++ ltpi->t_link_detect = ktime_get_ns(); ++ ++ /* LTPI initialization is required, start link training phase */ ++ do { ++ dev_info(ltpi->dev, "Starting LTPI link training\n"); ++ ltpi_do_link_training(ltpi); ++ do { ++ ret = ltpi_wait_state_pll_set(ltpi, 20000); ++ if (ret == 0) ++ break; ++ ++ if (ltpi->op_timeout && ++ (ktime_get_ns() - ltpi->t_link_detect > ++ ltpi->op_timeout)) { ++ dev_err(ltpi->dev, ++ "Timeout while waiting for PLL set state\n"); ++ ret = -ETIMEDOUT; ++ goto ltpi_scm_exit; ++ } ++ } while (1); ++ ++ /* read intersection of the speed capabilities */ ++ reg = FIELD_GET(REG_LTPI_SP_INTERSETION, ++ readl(ltpi->regs + LTPI_LINK_MNG_ST)); ++ if (reg == 0) { ++ dev_err(ltpi->dev, "No common speed\n"); ++ ret = -ENOLINK; ++ goto ltpi_scm_exit; ++ } ++ ++ target_speed = ltpi_set_operational_clk(ltpi, reg); ++ ++ /* poll link state 0x7 */ ++ ret = ltpi_wait_state_op(ltpi); ++ if (ret == 0) { ++ /* Start OEM TX & RX if the link partner is AST1700 */ ++ if (readl(ltpi->regs + LTPI_LINK_MNG_ST) & ++ REG_LTPI_LINK_PARTNER_FLAG) { ++ u32 val = readl(ltpi->regs + ++ LTPI_OEM_BUS_SETTING); ++ val |= (REG_LTPI_OEM_RX_START_TRIG | ++ REG_LTPI_OEM_TX_START_TRIG); ++ writel(val, ltpi->regs + LTPI_OEM_BUS_SETTING); ++ } ++ break; ++ } ++ ++ if (ltpi->op_timeout && ++ (ktime_get_ns() - ltpi->t_link_detect > ltpi->op_timeout)) { ++ dev_err(ltpi->dev, ++ "Timeout while waiting for operational state\n"); ++ ret = -ETIMEDOUT; ++ goto ltpi_scm_exit; ++ } ++ ++ if (!ltpi->disable_auto_downshift) ++ /* clear the bit to specify the current speed doesn't work */ ++ ltpi->phy_speed_cap &= ~BIT(target_speed); ++ ++ /* the lowest speed 25M should always be supported */ ++ if ((ltpi->phy_speed_cap & LTPI_SP_CAP_25M) == 0) ++ ltpi->phy_speed_cap |= LTPI_SP_CAP_25M; ++ ++ dev_warn(ltpi->dev, ++ "Failed to enter operational state, restarting link training\n"); ++ ltpi_dump(ltpi); ++ } while (1); ++ ++ dev_info(ltpi->dev, "LTPI Link trained successfully\n"); ++ return 0; ++ ++ltpi_scm_exit: ++ dev_err(ltpi->dev, "Exiting initialization\n"); ++ ltpi_dump(ltpi); ++ ltpi_reset(ltpi); ++ return ret; ++} ++ ++/* Sysfs attribute show/store functions */ ++static ssize_t ad_timeout_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", priv->ad_timeout); ++} ++ ++static ssize_t ad_timeout_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->ad_timeout = val; ++ return count; ++} ++ ++static ssize_t io_driving_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "0x%x\n", priv->io_driving); ++} ++ ++static ssize_t io_driving_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->io_driving = val; ++ return count; ++} ++ ++static ssize_t clk_inverse_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "0x%x\n", priv->clk_inverse); ++} ++ ++static ssize_t clk_inverse_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->clk_inverse = val; ++ return count; ++} ++ ++static ssize_t link_speed_frm_rx_cnt_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", priv->link_speed_frm_rx_cnt); ++} ++ ++static ssize_t link_speed_frm_rx_cnt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->link_speed_frm_rx_cnt = val; ++ return count; ++} ++ ++static ssize_t disable_auto_downshift_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", priv->disable_auto_downshift); ++} ++ ++static ssize_t disable_auto_downshift_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->disable_auto_downshift = val ? 1 : 0; ++ return count; ++} ++ ++static ssize_t crc_format_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", priv->crc_format); ++} ++ ++static ssize_t crc_format_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->crc_format = val ? 1 : 0; ++ return count; ++} ++ ++static ssize_t phy_speed_cap_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "0x%x\n", priv->phy_speed_cap); ++} ++ ++static ssize_t phy_speed_cap_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->phy_speed_cap = val; ++ return count; ++} ++ ++static ssize_t op_timeout_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%llu\n", priv->op_timeout); ++} ++ ++static ssize_t op_timeout_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ unsigned long long val; ++ ++ if (kstrtoull(buf, 0, &val)) ++ return -EINVAL; ++ ++ priv->op_timeout = val; ++ return count; ++} ++ ++static ssize_t rescan_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ u32 val, reg; ++ ++ if (kstrtouint(buf, 0, &val)) ++ return -EINVAL; ++ ++ if (val == 1 && priv->version == AST2700) { ++ dev_info(priv->dev, "Triggering LTPI rescan\n"); ++ if (ltpi_scm_init(priv)) { ++ dev_err(priv->dev, "LTPI rescan failed\n"); ++ return -EIO; ++ } ++ writel(LTPI_INTR_EN_OP_LINK_LOST, ++ priv->regs + LTPI_INTR_STATUS); ++ writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_EN); ++ aspeed_ltpi_init_mux(priv); ++ if (ltpi_get_link_partner(priv)) { ++ reg = FIELD_PREP(REG_LTPI_AHB_ADDR_MAP0, 0x5) | ++ FIELD_PREP(REG_LTPI_AHB_ADDR_MAP1, 0xa0); ++ } else { ++ reg = 0; ++ writel(0, priv->regs + LTPI_DATA_CH_CFG0); + } ++ writel(reg, priv->regs + LTPI_AHB_CTRL0); + } ++ ++ return count; +} + -+static const struct kcs_bmc_device_ops aspeed_kcs_ops = { -+ .io_inputb = aspeed_kcs_inb, -+ .io_outputb = aspeed_kcs_outb, -+ .io_updateb = aspeed_kcs_updateb, -+ .irq_mask_update = aspeed_kcs_irq_mask_update, ++static ssize_t link_status_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ u32 state = ltpi_get_link_mng_state(priv); ++ char state_str[128]; ++ int speed; ++ u32 phy_mode, clk_select; ++ char modes[9][8] = { "OFF", "SDR", "DDR", "NA", "CDR_LO", ++ "NA", "NA", "NA", "CDR_HI" }; ++ ++ if (state != LTPI_LINK_MNG_ST_OP) { ++ sprintf(state_str, "LTPI: not linked\n"); ++ } else { ++ phy_mode = FIELD_GET(REG_LTPI_PHY_MODE, readl(priv->phy_regs + LTPI_PHY_CTRL)); ++ clk_select = FIELD_GET(REG_LTPI_PLL_SELECT, readl(priv->phy_regs + LTPI_PLL_CTRL)); ++ if (clk_select == REG_LTPI_PLL_LPLL) ++ speed = scu_get_pll_freq(priv, priv->index) / 1000000; ++ else ++ speed = 25; ++ ++ sprintf(state_str, ++ "LTPI%d:\n" ++ " link partner : %s\n" ++ " link mode : %s\n" ++ " link bandwidth : %dMbps\n", ++ priv->index, ++ ltpi_get_link_partner(priv) ? "ast1700" : "fpga", ++ &modes[phy_mode][0], speed); ++ } ++ ++ return sprintf(buf, "%s\n", state_str); ++} ++ ++/* Device attributes */ ++static DEVICE_ATTR_RW(ad_timeout); ++static DEVICE_ATTR_RW(io_driving); ++static DEVICE_ATTR_RW(clk_inverse); ++static DEVICE_ATTR_RW(link_speed_frm_rx_cnt); ++static DEVICE_ATTR_RW(disable_auto_downshift); ++static DEVICE_ATTR_RW(crc_format); ++static DEVICE_ATTR_RW(phy_speed_cap); ++static DEVICE_ATTR_RW(op_timeout); ++static DEVICE_ATTR_WO(rescan); ++static DEVICE_ATTR_RO(link_status); ++ ++static struct attribute *aspeed_ltpi_attrs[] = { ++ &dev_attr_ad_timeout.attr, ++ &dev_attr_io_driving.attr, ++ &dev_attr_clk_inverse.attr, ++ &dev_attr_link_speed_frm_rx_cnt.attr, ++ &dev_attr_disable_auto_downshift.attr, ++ &dev_attr_crc_format.attr, ++ &dev_attr_phy_speed_cap.attr, ++ &dev_attr_op_timeout.attr, ++ &dev_attr_rescan.attr, ++ &dev_attr_link_status.attr, ++ NULL, +}; + - /* -- * We note D for Data, and C for Cmd/Status, default rules are -+ * Follow IPMI v2.0, given a KCS IO base X, -+ * the Data and Cmd/Status IO addresses are X and X+1. - * -- * 1. Only the D address is given: -- * A. KCS1/KCS2 (D/C: X/X+4) -- * D/C: CA0h/CA4h -- * D/C: CA8h/CACh -- * B. KCS3 (D/C: XX2/XX3h) -- * D/C: CA2h/CA3h -- * C. KCS4 (D/C: X/X+1) -- * D/C: CA4h/CA5h -- * -- * 2. Both the D/C addresses are given: -- * A. KCS1/KCS2/KCS4 (D/C: X/Y) -- * D/C: CA0h/CA1h -- * D/C: CA8h/CA9h -- * D/C: CA4h/CA5h -- * B. KCS3 (D/C: XX2/XX3h) -- * D/C: CA2h/CA3h -+ * Note that the IO base of KCS channel 3/7/11/... must ends with 2 -+ * e.g. CA2h for KCS#3 ++static const struct attribute_group aspeed_ltpi_attr_group = { ++ .attrs = aspeed_ltpi_attrs, ++}; ++ ++static int aspeed_ltpi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct of_dev_auxdata *lookup = dev_get_platdata(dev); ++ struct device_node *np = dev->of_node; ++ const struct of_device_id *match; ++ struct aspeed_ltpi_priv *priv; ++ int irq, ret; ++ struct resource *res; ++ ++ match = of_match_device(dev->driver->of_match_table, dev); ++ ++ if (match) { ++ if (of_property_match_string(np, "compatible", ++ match->compatible) < 0) ++ return -ENODEV; ++ } else { ++ return -ENODEV; ++ } ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ priv->regs = devm_platform_ioremap_resource_byname(pdev, "base"); ++ if (IS_ERR(priv->regs)) ++ priv->regs = ++ devm_platform_ioremap_resource(pdev, 0); // Fallback ++ if (IS_ERR(priv->regs)) ++ return PTR_ERR(priv->regs); ++ ++ priv->phy_regs = devm_platform_ioremap_resource_byname(pdev, "phy"); ++ if (IS_ERR(priv->phy_regs)) ++ priv->phy_regs = ++ priv->regs + 0x200; // Fallback unsafe if size small ++ ++ priv->top_regs = devm_platform_ioremap_resource_byname(pdev, "top"); ++ if (IS_ERR(priv->top_regs)) ++ priv->top_regs = ++ priv->regs + 0x800; // Fallback unsafe if size small ++ ++ /* Identify index based on physical address for PLL control */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res && (res->start & 0x1000)) ++ priv->index = 1; ++ else ++ priv->index = 0; ++ ++ priv->version = (enum chip_version)device_get_match_data(dev); ++ ++ priv->ltpi_clk = devm_clk_get(&pdev->dev, "ltpi"); ++ if (IS_ERR(priv->ltpi_clk)) { ++ priv->ltpi_clk = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(priv->ltpi_clk)) ++ return PTR_ERR(priv->ltpi_clk); ++ ++ clk_prepare_enable(priv->ltpi_clk); ++ ++ priv->ltpi_phyclk = devm_clk_get(&pdev->dev, "phy"); ++ if (IS_ERR(priv->ltpi_phyclk)) ++ return PTR_ERR(priv->ltpi_phyclk); ++ ++ clk_prepare_enable(priv->ltpi_phyclk); ++ } else { ++ priv->ltpi_phyclk = NULL; ++ } ++ ++ priv->ltpi_rst = ++ devm_reset_control_get_optional_shared(&pdev->dev, NULL); ++ if (IS_ERR(priv->ltpi_rst)) ++ return PTR_ERR(priv->ltpi_rst); ++ ++ reset_control_deassert(priv->ltpi_rst); ++ ++ priv->i2c_tunneling = GENMASK(MAX_I2C_IN_LTPI - 1, 0); ++ if (!of_property_read_u32(np, "i2c-tunneling", &ret)) ++ priv->i2c_tunneling = ret; ++ ++ priv->i2c_timing_0 = LTPI_I2C_100K_0; ++ priv->i2c_timing_1 = LTPI_I2C_100K_1; ++ if (!of_property_read_u32(np, "i2c-tunneling-timing", &ret)) { ++ if (ret == 400) { ++ priv->i2c_timing_0 = LTPI_I2C_400K_0; ++ priv->i2c_timing_1 = LTPI_I2C_400K_1; ++ } ++ } ++ priv->uart_tunneling = GENMASK(MAX_UART_IN_LTPI - 1, 0); ++ if (!of_property_read_u32(np, "uart-tunneling", &ret)) ++ priv->uart_tunneling = ret; ++ ++ priv->scu = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); ++ if (IS_ERR(priv->scu)) { ++ dev_err(&pdev->dev, "failed to get SCU regmap\n"); ++ return PTR_ERR(priv->scu); ++ } ++ if (of_get_property(np, "remote-controller", NULL)) { ++ u32 reg; ++ ++ /* Clear all the pins/otp strap but LTPI related settings for AST1700 */ ++ regmap_read(priv->scu, SCU_IO_PINS_TRAP1, ®); ++ reg &= ~SCU_IO_PINS_TRAP_LTPI; ++ regmap_write(priv->scu, SCU_IO_PINS_TRAP1_CLEAR, reg); ++ ++ regmap_read(priv->scu, SCU_IO_OTP_TRAP1, ®); ++ regmap_write(priv->scu, SCU_IO_OTP_TRAP1_CLEAR, reg); ++ ++ regmap_read(priv->scu, SCU_IO_OTP_TRAP2, ®); ++ regmap_write(priv->scu, SCU_IO_OTP_TRAP2_CLEAR, reg); ++ } else { ++ irq = platform_get_irq(pdev, 0); ++ ret = devm_request_irq(priv->dev, irq, aspeed_ltpi_irq_handler, ++ 0, dev_name(priv->dev), priv); ++ if (ret) { ++ dev_err(priv->dev, "failed to request irq\n"); ++ reset_control_assert(priv->ltpi_rst); ++ clk_disable_unprepare(priv->ltpi_phyclk); ++ clk_disable_unprepare(priv->ltpi_clk); ++ return ret; ++ } ++ ++ writel(LTPI_INTR_EN_OP_LINK_LOST, ++ priv->regs + LTPI_INTR_STATUS); ++ writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_EN); ++ } ++ ++ /* Initialize training parameters with defaults */ ++ priv->ad_timeout = ADVERTISE_TIMEOUT_US; ++ priv->io_driving = 0x2; ++ priv->clk_inverse = 0x0; ++ priv->link_speed_frm_rx_cnt = 0; ++ priv->disable_auto_downshift = 0; ++ priv->crc_format = 0; ++ priv->otp_ddr_dis = false; ++ priv->op_timeout = 2000000000; /* 2 seconds timeout by default */ ++ priv->phy_speed_cap = LTPI_SP_CAP_ASPEED_SUPPORTED; ++ ++ aspeed_ltpi_init_mux(priv); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ /* Create sysfs attributes */ ++ ret = sysfs_create_group(&dev->kobj, &aspeed_ltpi_attr_group); ++ if (ret) { ++ dev_err(dev, "Failed to create sysfs group\n"); ++ reset_control_assert(priv->ltpi_rst); ++ clk_disable_unprepare(priv->ltpi_phyclk); ++ clk_disable_unprepare(priv->ltpi_clk); ++ return ret; ++ } ++ ++ if (np) ++ of_platform_populate(np, NULL, lookup, priv->dev); ++ ++ return 0; ++} ++ ++static void aspeed_ltpi_remove(struct platform_device *pdev) ++{ ++ struct aspeed_ltpi_priv *priv; ++ ++ priv = platform_get_drvdata(pdev); ++ ++ /* Remove sysfs attributes */ ++ sysfs_remove_group(&pdev->dev.kobj, &aspeed_ltpi_attr_group); ++ ++ reset_control_assert(priv->ltpi_rst); ++ clk_disable_unprepare(priv->ltpi_phyclk); ++ clk_disable_unprepare(priv->ltpi_clk); ++} ++ ++static const struct of_device_id aspeed_ltpi_of_match[] = { ++ { ++ .compatible = "aspeed-ltpi", ++ .data = (const void *)AST2700, ++ }, ++ { ++ .compatible = "aspeed-ast1700-ltpi", ++ .data = (const void *)AST1700, ++ }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_ltpi_of_match); ++ ++static struct platform_driver aspeed_ltpi_driver = { ++ .probe = aspeed_ltpi_probe, ++ .remove = aspeed_ltpi_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_ltpi_of_match, ++ }, ++}; ++ ++module_platform_driver(aspeed_ltpi_driver); ++ ++MODULE_DESCRIPTION("LVDS Tunneling Protocol and Interface Bus Driver"); ++MODULE_AUTHOR("Dylan Hung "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/bus/aspeed-ltpi.h b/drivers/bus/aspeed-ltpi.h +--- a/drivers/bus/aspeed-ltpi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/bus/aspeed-ltpi.h 2026-09-09 15:51:44.532240882 +0000 +@@ -0,0 +1,275 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2024 ASPEED Technology Inc. ++ */ ++#ifndef __ASPEED_LTPI_H__ ++#define __ASPEED_LTPI_H__ ++ ++#include ++ ++/* OCP_DC-SCM_2.0_LTPI_ver_1.0, Table 21 LTPI speed capability encoding */ ++#define LTPI_SP_CAP_25M BIT(0) ++#define LTPI_SP_CAP_50M BIT(1) ++#define LTPI_SP_CAP_75M BIT(2) ++#define LTPI_SP_CAP_100M BIT(3) ++#define LTPI_SP_CAP_150M BIT(4) ++#define LTPI_SP_CAP_200M BIT(5) ++#define LTPI_SP_CAP_250M BIT(6) ++#define LTPI_SP_CAP_300M BIT(7) ++#define LTPI_SP_CAP_400M BIT(8) ++#define LTPI_SP_CAP_600M BIT(9) ++#define LTPI_SP_CAP_800M BIT(10) ++#define LTPI_SP_CAP_1G BIT(11) ++#define LTPI_SP_CAP_500M BIT(12) /* Aspeed only */ ++/* --gap-- */ ++#define LTPI_SP_CAP_DDR BIT(15) ++ ++#define LTPI_SP_CAP_ASPEED_SUPPORTED \ ++ (LTPI_SP_CAP_25M | LTPI_SP_CAP_50M | LTPI_SP_CAP_75M | \ ++ LTPI_SP_CAP_100M | LTPI_SP_CAP_150M | LTPI_SP_CAP_200M | \ ++ LTPI_SP_CAP_250M | LTPI_SP_CAP_300M | LTPI_SP_CAP_400M | \ ++ LTPI_SP_CAP_500M | LTPI_SP_CAP_DDR) ++ ++/* control registers */ ++#define LTPI_LINK_ST 0x000 ++#define REG_LTPI_LINK_ST_LOCAL GENMASK(19, 16) ++#define REG_LTPI_LINK_ST_REMOTE GENMASK(15, 12) ++#define REG_LTPI_LINK_SPEED GENMASK(11, 8) ++#define REG_LTPI_LINK_DDR_MODE BIT(7) ++#define REG_LTPI_LINK_ST_RESERVED BIT(6) ++#define REG_LTPI_CON_ACC_TO_ERR BIT(5) ++#define REG_LTPI_LINK_SP_TO_ERR BIT(4) ++#define REG_LTPI_UNKNOWN_COMMA_ERR BIT(3) ++#define REG_LTPI_FRM_CRC_ERR BIT(2) ++#define REG_LTPI_LINK_LOST_ERR BIT(1) ++#define REG_LTPI_LINK_ALIGN BIT(0) ++ ++#define LTPI_CAP_LOCAL 0x004 ++#define REG_LTPI_SP_CAP_LOCAL GENMASK(23, 8) ++#define REG_LTPI_MAJOR_VER_LOCAL GENMASK(7, 4) ++#define REG_LTPI_MIN_VER_LOCAL GENMASK(3, 0) ++#define LTPI_CAP_REMOTE 0x008 ++#define REG_LTPI_SP_CAP_REMOTE GENMASK(23, 8) ++#define REG_LTPI_MAJOR_VER_REMOTE GENMASK(7, 4) ++#define REG_LTPI_MIN_VER_REMOTE GENMASK(3, 0) ++#define LTPI_PF_ID_LOCAL 0x00C ++#define LTPI_PF_ID_REMOTE 0x010 ++#define LTPI_AD_CAP_LOW_LOCAL 0x014 ++#define LTPI_AD_CAP_HIGH_LOCAL 0x018 ++#define LTPI_AD_CAP_LOW_REMOTE 0x01C ++#define LTPI_AD_CAP_HIGH_REMOTE 0x020 ++#define LTPI_DEFAULT_CON_LOW 0x024 ++#define LTPI_DEFAULT_CON_HIGH 0x028 ++#define LTPI_LINK_ALIGN_ERR_CNT 0x02C ++#define LTPI_LINK_LOST_ERR_CNT 0x030 ++#define LTPI_CRC_ERR_CNT 0x034 ++#define LTPI_UNKNOWN_COMMA_ERR_CNT 0x038 ++#define LTPI_LINK_SP_TO_ERR_CNT 0x03C ++#define LTPI_CON_ACC_TO_ERR_CNT 0x040 ++#define LTPI_LINK_TRAIN_RX_FRM_CNT_LOW 0x044 ++#define REG_LTPI_CON_ACC_FRM_RX_CNT GENMASK(31, 24) ++#define REG_LTPI_LINK_SP_FRM_RX_CNT GENMASK(23, 16) ++#define REG_LTPI_LINK_DET_FRM_RX_CNT GENMASK(15, 0) ++#define LTPI_LINK_TRAIN_RX_FRM_CNT_HIGH 0x048 ++#define LTPI_LINK_TRAIN_TX_FRM_CNT_LOW 0x04C ++#define REG_LTPI_CON_ACC_FRM_TX_CNT GENMASK(31, 24) ++#define REG_LTPI_LINK_SP_FRM_TX_CNT GENMASK(23, 16) ++#define REG_LTPI_LINK_DET_FRM_TX_CNT GENMASK(15, 0) ++#define LTPI_LINK_TRAIN_TX_FRM_CNT_HIGH 0x050 ++#define LTPI_OP_RX_FRM_CNT 0x054 ++#define LTPI_OP_TX_FRM_CNT 0x058 ++#define LTPI_LINK_LOST_CNT 0x05c ++#define REG_LTPI_AD_ALIGN_TO_CNT GENMASK(27, 24) ++#define REG_LTPI_LINK_LOST_OP_CNT GENMASK(23, 16) ++#define REG_LTPI_LINK_LOST_CON_OR_ACC_CNT GENMASK(15, 8) ++#define REG_LTPI_LINK_LOST_AD_CNT GENMASK(7, 0) ++#define LTPI_LINK_CONTROL 0x080 ++#define REG_LTPI_TRIG_CON_ST BIT(11) ++#define REG_LTPI_AUTO_CON_ST BIT(10) ++#define REG_LTPI_DATA_CH_RST BIT(9) ++#define REG_LTPI_I2C_RST GENMASK(8, 2) ++#define REG_LTPI_LINK_RETRAIN_REQ BIT(1) ++#define REG_LTPI_LINK_SW_RST BIT(0) ++ ++#define LTPI_INTR 0x100 ++#define REG_LTPI_LINK_HALT BIT(24) ++#define REG_LTPI_DATA_CH_DROP_FRAME BIT(23) ++#define REG_LTPI_DATA_CH_INVALID_ACCESS BIT(22) ++#define REG_LTPI_I2C5_TO_ERR BIT(21) ++#define REG_LTPI_I2C4_TO_ERR BIT(20) ++#define REG_LTPI_I2C3_TO_ERR BIT(19) ++#define REG_LTPI_I2C2_TO_ERR BIT(18) ++#define REG_LTPI_I2C1_TO_ERR BIT(17) ++#define REG_LTPI_I2C0_TO_ERR BIT(16) ++#define REG_LTPI_AD_ALIGN_TO BIT(12) ++#define REG_LTPI_HW_RETRY_LINK_DET_STUCK_TO_ERR BIT(11) ++#define REG_LTPI_HW_RETRY_TO_ERR BIT(10) ++#define REG_LTPI_OP_LINK_LOST_ERR BIT(4) ++#define REG_LTPI_CON_OR_ACC_LINK_LOST_ERR BIT(3) ++#define REG_LTPI_AD_LINK_LOST_ERR BIT(2) ++#define REG_LTPI_CON_READY BIT(1) ++#define REG_LTPI_AD_READY BIT(0) ++#define LTPI_INTR_EN 0x104 ++#define REG_LTPI_LINK_HALT_INTR_EN BIT(24) ++#define REG_LTPI_DATA_CH_DROP_FRAME_EN BIT(23) ++#define REG_LTPI_DATA_CH_INVALID_ACCESS_EN BIT(22) ++#define REG_LTPI_I2C5_TO_ERR_EN BIT(21) ++#define REG_LTPI_I2C4_TO_ERR_EN BIT(20) ++#define REG_LTPI_I2C3_TO_ERR_EN BIT(19) ++#define REG_LTPI_I2C2_TO_ERR_EN BIT(18) ++#define REG_LTPI_I2C1_TO_ERR_EN BIT(17) ++#define REG_LTPI_I2C0_TO_ERR_EN BIT(16) ++#define REG_LTPI_AD_ALIGN_TO_EN BIT(12) ++#define REG_LTPI_HW_RETRY_LINK_DET_STUCK_TO_ERR_EN BIT(11) ++#define REG_LTPI_HW_RETRY_TO_ERR_EN BIT(10) ++#define REG_LTPI_CON_ACC_TO_ERR_EN BIT(9) ++#define REG_LTPI_LINK_SP_TO_ERR_EN BIT(8) ++#define REG_LTPI_UNKNOWN_COMMA_ERR_EN BIT(7) ++#define REG_LTPI_FRM_CRC_ERR_EN BIT(6) ++#define REG_LTPI_LINK_LOST_ERR_EN BIT(5) ++#define REG_LTPI_OP_LINK_LOST_ERR_EN BIT(4) ++#define REG_LTPI_CON_OR_ACC_LINK_LOST_ERR_EN BIT(3) ++#define REG_LTPI_AD_LINK_LOST_ERR_EN BIT(2) ++#define REG_LTPI_CON_READY_EN BIT(1) ++#define REG_LTPI_AD_READY_EN BIT(0) ++#define LTPI_LINK_MNG_ST 0x108 ++#define REG_LTPI_LINK_PARTNER_FLAG BIT(24) ++#define REG_LTPI_LINK_PARTNER_FPGA 0b0 ++#define REG_LTPI_LINK_PARTNER_1700 0b1 ++#define REG_LTPI_SP_INTERSETION GENMASK(23, 8) ++#define REG_LTPI_LINK_MNG_ST GENMASK(3, 0) ++#define LTPI_LINK_MNG_ST_DETECT_ALIGN 0 ++#define LTPI_LINK_MNG_ST_DETECT 1 ++#define LTPI_LINK_MNG_ST_SPEED 2 ++#define LTPI_LINK_MNG_ST_WAIT_PLL_SET 3 ++#define LTPI_LINK_MNG_ST_ADV_ALIGN 4 ++#define LTPI_LINK_MNG_ST_ADV 5 ++#define LTPI_LINK_MNG_ST_CONFIG_ACC 6 ++#define LTPI_LINK_MNG_ST_OP 7 ++#define LTPI_LINK_MANAGE_CTRL0 0x10C ++#define REG_LTPI_LINK_PARTNER_CHKNUM GENMASK(19, 16) ++#define REG_LTPI_CON_FRM_NOCHK BIT(8) ++#define REG_LTPI_TX_LINK_SP_FRM_NUM GENMASK(7, 4) ++#define REG_LTPI_RX_LINK_SP_FRM_NUM GENMASK(3, 0) ++#define LTPI_LINK_MANAGE_CTRL1 0x110 ++#define LTPI_LINK_MANAGE_CTRL2 0x114 ++#define LTPI_CON_CAP_LOW 0x118 ++#define LTPI_CON_CAP_HIGH 0x11C ++#define LTPI_MAC_CTRL 0x120 ++#define LTPI_AHB_CTRL0 0x124 ++#define REG_LTPI_AHB_ADDR_MAP1 GENMASK(25, 16) ++#define REG_LTPI_AHB_ADDR_MAP0 GENMASK(9, 0) ++#define LTPI_AHB_CTRL1 0x128 ++#define REG_LTPI_AHB_ADDR_MAP3 GENMASK(25, 16) ++#define REG_LTPI_AHB_ADDR_MAP2 GENMASK(9, 0) ++#define LTPI_CRC_OPTION 0x12c ++#define REG_LTPI_SW_CRC_OUT_ML_FIRST BIT(2) ++#define REG_LTPI_SW_CRC_IN_LSB_FIRST BIT(1) ++#define REG_LTPI_CRC_SW_FORCE BIT(0) ++#define LTPI_I2C 0x130 ++#define REG_LTPI_I2C_SLV_MST_SWITCH_SW_EN BIT(8) ++#define REG_LTPI_I2C_SLV_EN GENMASK(5, 0) ++ ++#define LTPI_OEM_BUS_SETTING 0x188 ++#define REG_LTPI_OEM_RX_START_TRIG BIT(1) ++#define REG_LTPI_OEM_TX_START_TRIG BIT(0) ++ ++#define LTPI_OEM_DBG0 0x190 ++#define REG_LTPI_OEM_RX_INIT_DONE BIT(9) ++#define REG_LTPI_OEM_TX_INIT_DONE BIT(8) ++ ++#define LTPI_DATA_CH_CFG0 0x1D8 ++#define REG_LTPI_DATA_CH_TAG_CHK_EN BIT(2) ++#define REG_LTPI_DATA_CH_ADDR_CHK_EN BIT(1) ++#define REG_LTPI_DATA_CH_WAIT_ACK_TO_EN BIT(0) ++ ++/* LTPI PHY control registers */ ++#define LTPI_PHY_CTRL 0x000 ++#define REG_LTPI_PHY_MODE GENMASK(3, 0) ++#define LTPI_PHY_MODE_CDR_HI_SP 0b1000 ++#define LTPI_PHY_MODE_CDR_LO_SP 0b0100 ++#define LTPI_PHY_MODE_DDR 0b0010 ++#define LTPI_PHY_MODE_SDR 0b0001 ++#define LTPI_PHY_MODE_OFF 0b0000 ++#define LTPI_PLL_CTRL 0x004 ++#define REG_LTPI_RX_PHY_CLK_INV BIT(9) ++#define REG_LTPI_TX_PHY_CLK_INV BIT(8) ++#define REG_LTPI_PLL_SET BIT(4) ++#define REG_LTPI_RX_PLL_DIV2 BIT(3) ++#define REG_LTPI_PLL_SELECT GENMASK(2, 0) ++#define REG_LTPI_PLL_25M 0 ++/* AST2700A0 */ ++#define REG_LTPI_PLL_50M 1 ++#define REG_LTPI_PLL_100M 2 ++#define REG_LTPI_PLL_200M 3 ++#define REG_LTPI_PLL_250M 4 ++#define REG_LTPI_PLL_400M 5 ++#define REG_LTPI_PLL_800M 6 ++#define REG_LTPI_PLL_1G 7 ++/* AST2700A1 */ ++#define REG_LTPI_PLL_LPLL 7 ++ ++#define LTPI_PHY_ALIGN_CTRL 0x008 ++#define LTPI_DLL_CTRL 0x00C ++#define REG_LTPI_SW_DLL_RST BIT(26) ++#define REG_LTPI_FORCE_DLL_RST BIT(25) ++#define REG_LTPI_DLL_PD BIT(24) ++#define REG_LTPI_DLL_TSTCTRL GENMASK(23, 16) ++#define REG_LTPI_DLL_RST_TIMEOUT_A0 GENMASK(15, 0) ++#define REG_LTPI_DLL_CLK_2X BIT(8) ++#define REG_LTPI_DLL_RST_TIMEOUT GENMASK(7, 0) ++#define LTPI_PHY_HI_SP_CDR_CTRL 0x010 ++#define REG_LTPI_SW_HI_SP_CDR_EN BIT(10) ++#define REG_LTPI_FORCE_HI_SP_CDR_EN BIT(9) ++#define REG_LTPI_HI_SP_CDR_EN_TIMEOUT_EN BIT(8) ++#define LTPI_HI_SP_CDR_EN_TIMEOUT GENMASK(7, 0) ++ ++#define LTPI_PROT_KEY 0x34 ++#define LTPI_PROT_KEY_UNLOCK 0x1728aacc ++ ++/* LVDS TOP registers */ ++#define LTPI_LVDS_TX_CTRL 0x000 ++#define REG_LTPI_LVDS_TX1_DS1 BIT(22) ++#define REG_LTPI_LVDS_TX1_DS0 BIT(21) ++#define REG_LTPI_LVDS_TX1_IPREE BIT(20) ++#define REG_LTPI_LVDS_TX1_IPREE_EN BIT(19) ++#define REG_LTPI_LVDS_TX1_PD BIT(18) ++#define REG_LTPI_LVDS_TX1_PU BIT(17) ++#define REG_LTPI_LVDS_TX1_OE BIT(16) ++#define REG_LTPI_LVDS_TX0_DS1 BIT(6) ++#define REG_LTPI_LVDS_TX0_DS0 BIT(5) ++#define REG_LTPI_LVDS_TX0_IPREE BIT(4) ++#define REG_LTPI_LVDS_TX0_IPREE_EN BIT(3) ++#define REG_LTPI_LVDS_TX0_PD BIT(2) ++#define REG_LTPI_LVDS_TX0_PU BIT(1) ++#define REG_LTPI_LVDS_TX0_OE BIT(0) ++#define LTPI_LVDS_RX_CTRL 0x004 ++#define REG_LTPI_LVDS_RX1_BIAS_EN BIT(18) ++#define REG_LTPI_LVDS_RX1_ST BIT(17) ++#define REG_LTPI_LVDS_RX1_IE BIT(16) ++#define REG_LTPI_LVDS_RX0_BIAS_EN BIT(2) ++#define REG_LTPI_LVDS_RX0_ST BIT(1) ++#define REG_LTPI_LVDS_RX0_IE BIT(0) ++#define LTPI_SW_RST 0x008 ++#define REG_LTPI_ALL_SW_RST BIT(31) ++#define REG_LTPI1_SW_RST BIT(17) ++#define REG_LTPI0_SW_RST BIT(16) ++#define REG_LTPI_DLL_CTRL_SW_RST BIT(9) ++#define REG_LTPI_REF_SW_RST BIT(8) ++#define REG_LTPI1_RX_PHY_SW_RST BIT(7) ++#define REG_LTPI1_TX_PHY_SW_RST BIT(6) ++#define REG_LTPI1_RX_MAC_SW_RST BIT(5) ++#define REG_LTPI1_TX_MAC_SW_RST BIT(4) ++#define REG_LTPI0_RX_PHY_SW_RST BIT(3) ++#define REG_LTPI0_TX_PHY_SW_RST BIT(2) ++#define REG_LTPI0_RX_MAC_SW_RST BIT(1) ++#define REG_LTPI0_TX_MAC_SW_RST BIT(0) ++#define LTPI_STRAP_VAL 0x00c ++#define REG_LTPI_STRAP_2LTPI_EN BIT(1) ++#define REG_LTPI_STRAP_1700_EN BIT(0) ++#define LTPI_SW_FORCE_EN 0x010 ++#define LTPI_SW_FORCE_VAL 0x014 ++#define REG_LTPI_SW_FORCE_LVDS_TX_DS_EN BIT(1) ++#define REG_LTPI_SW_FORCE_1700_EN BIT(0) ++ ++#endif /* __ASPEED_LTPI_H__ */ +diff --git a/drivers/char/hw_random/aspeed-rng.c b/drivers/char/hw_random/aspeed-rng.c +--- a/drivers/char/hw_random/aspeed-rng.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/aspeed-rng.c 2026-09-09 15:51:44.684238585 +0000 +@@ -0,0 +1,134 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) ASPEED Technology Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TRNG_CTL 0x00 ++#define TRNG_EN 0x0 ++#define TRNG_MODE 0x04 ++#define TRNG_RDY 0x1f ++#define TRNG_ODATA 0x04 ++ ++struct aspeed_trng { ++ u32 ver; ++ void __iomem *base; ++ struct hwrng rng; ++ unsigned int present: 1; ++ ktime_t period; ++ struct hrtimer timer; ++ struct completion completion; ++}; ++ ++static int aspeed_trng_read(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ struct aspeed_trng *priv = container_of(rng, struct aspeed_trng, rng); ++ u32 *data = buf; ++ size_t read = 0; ++ int timeout = max / 4 + 1; ++ ++ while (read < max) { ++ if (!(readl(priv->base + TRNG_CTL) & (1 << TRNG_RDY))) { ++ if (wait) { ++ if (timeout-- == 0) ++ return read; ++ } else { ++ return 0; ++ } ++ } else { ++ *data = readl(priv->base + TRNG_ODATA); ++ data++; ++ read += 4; ++ } ++ } ++ ++ return read; ++} ++ ++static void aspeed_trng_enable(struct aspeed_trng *priv) ++{ ++ u32 ctl; ++ ++ ctl = readl(priv->base + TRNG_CTL); ++ ctl = ctl & ~(1 << TRNG_EN); /* enable rng */ ++ ctl = ctl | (3 << TRNG_MODE); /* select mode */ ++ ++ writel(ctl, priv->base + TRNG_CTL); ++} ++ ++static void aspeed_trng_disable(struct aspeed_trng *priv) ++{ ++ writel(1, priv->base + TRNG_CTL); ++} ++ ++static int aspeed_trng_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct aspeed_trng *priv; ++ struct resource *res; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ priv->rng.name = pdev->name; ++ priv->rng.quality = 900; ++ priv->rng.read = aspeed_trng_read; ++ ++ aspeed_trng_enable(priv); ++ ++ ret = devm_hwrng_register(&pdev->dev, &priv->rng); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ dev_info(dev, "Aspeed Hardware RNG successfully registered\n"); ++ ++ return 0; ++} ++ ++static void aspeed_trng_remove(struct platform_device *pdev) ++{ ++ struct aspeed_trng *priv = platform_get_drvdata(pdev); ++ ++ aspeed_trng_disable(priv); ++} ++ ++static const struct of_device_id aspeed_trng_dt_ids[] = { ++ { .compatible = "aspeed,ast2600-trng" }, ++ { .compatible = "aspeed,ast2700-trng" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, aspeed_trng_dt_ids); ++ ++static struct platform_driver aspeed_trng_driver = { ++ .probe = aspeed_trng_probe, ++ .remove = aspeed_trng_remove, ++ .driver = { ++ .name = "aspeed-trng", ++ .of_match_table = aspeed_trng_dt_ids, ++ }, ++}; ++ ++module_platform_driver(aspeed_trng_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Neal Liu "); ++MODULE_DESCRIPTION("Aspeed true random number generator driver"); +diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c +--- a/drivers/char/ipmi/kcs_bmc_aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/char/ipmi/kcs_bmc_aspeed.c 2026-09-09 15:51:44.691238480 +0000 +@@ -1,13 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0 + /* + * Copyright (c) 2015-2018, Intel Corporation. ++ * Copyright (c) 2023, Aspeed Technology Inc. */ --static int aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u32 addrs[2], int nr_addrs) -+static int aspeed_kcs_config_io_address(struct aspeed_kcs_bmc *kcs_aspeed) - { -- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); -+ u32 io_addr; - -- if (WARN_ON(nr_addrs < 1 || nr_addrs > 2)) -- return -EINVAL; -+ io_addr = kcs_aspeed->io_addr; - -- switch (priv->kcs_bmc.channel) { -+ switch (kcs_aspeed->hw_inst) { -+ case 0: -+ regmap_update_bits(kcs_aspeed->map, HICR4, HICR4_LADR12AS, 0); -+ regmap_write(kcs_aspeed->map, LADR12H, io_addr >> 8); -+ regmap_write(kcs_aspeed->map, LADR12L, io_addr & 0xFF); -+ regmap_update_bits(kcs_aspeed->map, LSADR12, LSADR12_LSADR1, -+ FIELD_PREP(LSADR12_LSADR1, io_addr + 1)); -+ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_EN16LADR1, -+ HICRB_EN16LADR1); -+ break; - case 1: -- regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, 0); -- regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8); -- regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF); -- if (nr_addrs == 2) { -- regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR1_MASK, -- addrs[1] << LPC_LSADR12_LSADR1_SHIFT); -- -- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR1, -- LPC_HICRB_EN16LADR1); -- } -+ regmap_update_bits(kcs_aspeed->map, HICR4, HICR4_LADR12AS, HICR4_LADR12AS); -+ regmap_write(kcs_aspeed->map, LADR12H, io_addr >> 8); -+ regmap_write(kcs_aspeed->map, LADR12L, io_addr & 0xFF); -+ regmap_update_bits(kcs_aspeed->map, LSADR12, LSADR12_LSADR2, -+ FIELD_PREP(LSADR12_LSADR2, io_addr + 1)); -+ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_EN16LADR2, -+ HICRB_EN16LADR2); - break; -- - case 2: -- regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS); -- regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8); -- regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF); -- if (nr_addrs == 2) { -- regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR2_MASK, -- addrs[1] << LPC_LSADR12_LSADR2_SHIFT); -- -- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR2, -- LPC_HICRB_EN16LADR2); -- } -+ regmap_write(kcs_aspeed->map, LADR3H, io_addr >> 8); -+ regmap_write(kcs_aspeed->map, LADR3L, io_addr & 0xFF); - break; -- - case 3: -- if (nr_addrs == 2) { -- dev_err(priv->kcs_bmc.dev, -- "Channel 3 only supports inferred status IO address\n"); -- return -EINVAL; -- } -- -- regmap_write(priv->map, LPC_LADR3H, addrs[0] >> 8); -- regmap_write(priv->map, LPC_LADR3L, addrs[0] & 0xFF); -+ regmap_write(kcs_aspeed->map, LADR4, ((io_addr + 1) << 16) | io_addr); - break; -- -- case 4: -- if (nr_addrs == 1) -- regmap_write(priv->map, LPC_LADR4, ((addrs[0] + 1) << 16) | addrs[0]); -- else -- regmap_write(priv->map, LPC_LADR4, (addrs[1] << 16) | addrs[0]); -- -- break; - - default: - return -EINVAL; - } -@@ -285,398 +309,283 @@ - return 0; - } + #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt --static inline int aspeed_kcs_map_serirq_type(u32 dt_type) --{ -- switch (dt_type) { -- case IRQ_TYPE_EDGE_RISING: -- return LPC_TYIRQX_RISING; -- case IRQ_TYPE_LEVEL_HIGH: -- return LPC_TYIRQX_HIGH; -- case IRQ_TYPE_LEVEL_LOW: -- return LPC_TYIRQX_LOW; -- default: -- return -EINVAL; -- } --} -- --static int aspeed_kcs_config_upstream_irq(struct aspeed_kcs_bmc *priv, u32 id, u32 dt_type) -+static int aspeed_kcs_config_upstream_serirq(struct aspeed_kcs_bmc *kcs_aspeed) - { -- unsigned int mask, val, hw_type; -- int ret; -+ unsigned int mask, val; -+ u32 sirq_id, sirq_type; + #include + #include + #include ++#include + #include + #include + #include +@@ -23,10 +24,9 @@ -- if (id > 15) -- return -EINVAL; -- -- ret = aspeed_kcs_map_serirq_type(dt_type); -- if (ret < 0) -- return ret; -- hw_type = ret; -+ if (kcs_aspeed->sirq.type == IRQ_TYPE_NONE) -+ return 0; + #include "kcs_bmc_device.h" -- priv->upstream_irq.mode = aspeed_kcs_irq_serirq; -- priv->upstream_irq.id = id; -+ sirq_id = kcs_aspeed->sirq.id; -+ sirq_type = kcs_aspeed->sirq.type; ++#define DEVICE_NAME "aspeed-kcs-bmc" -- switch (priv->kcs_bmc.channel) { -- case 1: -+ switch (kcs_aspeed->hw_inst) { -+ case 0: - /* Needs IRQxE1 rather than (ID1IRQX, SEL1IRQX, IRQXE1) before AST2600 A3 */ - break; -+ case 1: -+ mask = HICR5_SEL2IRQX | HICR5_ID2IRQX; -+ val = FIELD_PREP(HICR5_ID2IRQX, sirq_id); -+ val |= (sirq_type == IRQ_TYPE_LEVEL_HIGH) ? HICR5_SEL2IRQX : 0; -+ regmap_update_bits(kcs_aspeed->map, HICR5, mask, val); -+ break; - case 2: -- if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH)) -- return -EINVAL; -- -- mask = LPC_HICR5_SEL2IRQX | LPC_HICR5_ID2IRQX_MASK; -- val = (id << LPC_HICR5_ID2IRQX_SHIFT); -- val |= (hw_type == LPC_TYIRQX_HIGH) ? LPC_HICR5_SEL2IRQX : 0; -- regmap_update_bits(priv->map, LPC_HICR5, mask, val); +-#define DEVICE_NAME "ast-kcs-bmc" - -+ mask = HICR5_SEL3IRQX | HICR5_ID3IRQX; -+ val = FIELD_PREP(HICR5_ID3IRQX, sirq_id); -+ val |= (sirq_type == IRQ_TYPE_LEVEL_HIGH) ? HICR5_SEL3IRQX : 0; -+ regmap_update_bits(kcs_aspeed->map, HICR5, mask, val); - break; - case 3: -- if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH)) -- return -EINVAL; +-#define KCS_CHANNEL_MAX 4 ++static DEFINE_IDA(aspeed_kcs_bmc_ida); + + /* + * Field class descriptions +@@ -38,87 +38,74 @@ + * SELyIRQX SerIRQ polarity for LPC channel y (low: 0, high: 1) + * IRQXEy Assert the SerIRQ specified in IDyIRQX for LPC channel y + */ - -- mask = LPC_HICR5_SEL3IRQX | LPC_HICR5_ID3IRQX_MASK; -- val = (id << LPC_HICR5_ID3IRQX_SHIFT); -- val |= (hw_type == LPC_TYIRQX_HIGH) ? LPC_HICR5_SEL3IRQX : 0; -- regmap_update_bits(priv->map, LPC_HICR5, mask, val); +-#define LPC_TYIRQX_LOW 0b00 +-#define LPC_TYIRQX_HIGH 0b01 +-#define LPC_TYIRQX_RSVD 0b10 +-#define LPC_TYIRQX_RISING 0b11 - -- break; -- case 4: -- mask = LPC_HICRC_ID4IRQX_MASK | LPC_HICRC_TY4IRQX_MASK | LPC_HICRC_OBF4_AUTO_CLR; -- val = (id << LPC_HICRC_ID4IRQX_SHIFT) | (hw_type << LPC_HICRC_TY4IRQX_SHIFT); -- regmap_update_bits(priv->map, LPC_HICRC, mask, val); -+ mask = HICRC_ID4IRQX | HICRC_SEL4IRQX | HICRC_OBF4_AUTO_CLR; -+ val = FIELD_PREP(HICRC_ID4IRQX, sirq_id); -+ val |= (sirq_type == IRQ_TYPE_LEVEL_HIGH) ? HICRC_SEL4IRQX : 0; -+ regmap_update_bits(kcs_aspeed->map, HICRC, mask, val); - break; - default: -- dev_warn(priv->kcs_bmc.dev, -+ dev_warn(kcs_aspeed->kcs_bmc.dev, - "SerIRQ configuration not supported on KCS channel %d\n", -- priv->kcs_bmc.channel); -+ kcs_aspeed->kcs_bmc.channel); - return -EINVAL; - } - +-#define LPC_HICR0 0x000 +-#define LPC_HICR0_LPC3E BIT(7) +-#define LPC_HICR0_LPC2E BIT(6) +-#define LPC_HICR0_LPC1E BIT(5) +-#define LPC_HICR2 0x008 +-#define LPC_HICR2_IBFIE3 BIT(3) +-#define LPC_HICR2_IBFIE2 BIT(2) +-#define LPC_HICR2_IBFIE1 BIT(1) +-#define LPC_HICR4 0x010 +-#define LPC_HICR4_LADR12AS BIT(7) +-#define LPC_HICR4_KCSENBL BIT(2) +-#define LPC_SIRQCR0 0x070 ++#define HICR0 0x000 ++#define HICR0_LPC3E BIT(7) ++#define HICR0_LPC2E BIT(6) ++#define HICR0_LPC1E BIT(5) ++#define HICR2 0x008 ++#define HICR2_IBFIE3 BIT(3) ++#define HICR2_IBFIE2 BIT(2) ++#define HICR2_IBFIE1 BIT(1) ++#define HICR4 0x010 ++#define HICR4_LADR12AS BIT(7) ++#define HICR4_KCSENBL BIT(2) ++#define LADR3H 0x014 ++#define LADR3L 0x018 ++#define LADR12H 0x01C ++#define LADR12L 0x020 ++#define IDR1 0x024 ++#define IDR2 0x028 ++#define IDR3 0x02C ++#define ODR1 0x030 ++#define ODR2 0x034 ++#define ODR3 0x038 ++#define STR1 0x03C ++#define STR2 0x040 ++#define STR3 0x044 ++#define SIRQCR0 0x070 + /* IRQ{12,1}E1 are deprecated as of AST2600 A3 but necessary for prior chips */ +-#define LPC_SIRQCR0_IRQ12E1 BIT(1) +-#define LPC_SIRQCR0_IRQ1E1 BIT(0) +-#define LPC_HICR5 0x080 +-#define LPC_HICR5_ID3IRQX_MASK GENMASK(23, 20) +-#define LPC_HICR5_ID3IRQX_SHIFT 20 +-#define LPC_HICR5_ID2IRQX_MASK GENMASK(19, 16) +-#define LPC_HICR5_ID2IRQX_SHIFT 16 +-#define LPC_HICR5_SEL3IRQX BIT(15) +-#define LPC_HICR5_IRQXE3 BIT(14) +-#define LPC_HICR5_SEL2IRQX BIT(13) +-#define LPC_HICR5_IRQXE2 BIT(12) +-#define LPC_LADR3H 0x014 +-#define LPC_LADR3L 0x018 +-#define LPC_LADR12H 0x01C +-#define LPC_LADR12L 0x020 +-#define LPC_IDR1 0x024 +-#define LPC_IDR2 0x028 +-#define LPC_IDR3 0x02C +-#define LPC_ODR1 0x030 +-#define LPC_ODR2 0x034 +-#define LPC_ODR3 0x038 +-#define LPC_STR1 0x03C +-#define LPC_STR2 0x040 +-#define LPC_STR3 0x044 +-#define LPC_HICRB 0x100 +-#define LPC_HICRB_EN16LADR2 BIT(5) +-#define LPC_HICRB_EN16LADR1 BIT(4) +-#define LPC_HICRB_IBFIE4 BIT(1) +-#define LPC_HICRB_LPC4E BIT(0) +-#define LPC_HICRC 0x104 +-#define LPC_HICRC_ID4IRQX_MASK GENMASK(7, 4) +-#define LPC_HICRC_ID4IRQX_SHIFT 4 +-#define LPC_HICRC_TY4IRQX_MASK GENMASK(3, 2) +-#define LPC_HICRC_TY4IRQX_SHIFT 2 +-#define LPC_HICRC_OBF4_AUTO_CLR BIT(1) +-#define LPC_HICRC_IRQXE4 BIT(0) +-#define LPC_LADR4 0x110 +-#define LPC_IDR4 0x114 +-#define LPC_ODR4 0x118 +-#define LPC_STR4 0x11C +-#define LPC_LSADR12 0x120 +-#define LPC_LSADR12_LSADR2_MASK GENMASK(31, 16) +-#define LPC_LSADR12_LSADR2_SHIFT 16 +-#define LPC_LSADR12_LSADR1_MASK GENMASK(15, 0) +-#define LPC_LSADR12_LSADR1_SHIFT 0 +- +-#define OBE_POLL_PERIOD (HZ / 2) +- +-enum aspeed_kcs_irq_mode { +- aspeed_kcs_irq_none, +- aspeed_kcs_irq_serirq, +-}; ++#define SIRQCR0_IRQ12E1 BIT(1) ++#define SIRQCR0_IRQ1E1 BIT(0) ++#define HICR5 0x080 ++#define HICR5_ID3IRQX GENMASK(23, 20) ++#define HICR5_ID2IRQX GENMASK(19, 16) ++#define HICR5_SEL3IRQX BIT(15) ++#define HICR5_IRQXE3 BIT(14) ++#define HICR5_SEL2IRQX BIT(13) ++#define HICR5_IRQXE2 BIT(12) ++#define HICRB 0x100 ++#define HICRB_EN16LADR2 BIT(5) ++#define HICRB_EN16LADR1 BIT(4) ++#define HICRB_IBFIE4 BIT(1) ++#define HICRB_LPC4E BIT(0) ++#define HICRC 0x104 ++#define HICRC_ID4IRQX GENMASK(7, 4) ++#define HICRC_SEL4IRQX BIT(2) ++#define HICRC_OBF4_AUTO_CLR BIT(1) ++#define HICRC_IRQXE4 BIT(0) ++#define LADR4 0x110 ++#define IDR4 0x114 ++#define ODR4 0x118 ++#define STR4 0x11C ++#define LSADR12 0x120 ++#define LSADR12_LSADR2 GENMASK(31, 16) ++#define LSADR12_LSADR1 GENMASK(15, 0) ++ ++#define KCS_HW_INSTANCE_NUM 4 ++#define KCS_OBE_POLL_PERIOD (HZ / 2) + + struct aspeed_kcs_bmc { + struct kcs_bmc_device kcs_bmc; +- + struct regmap *map; ++ int irq; ++ ++ u32 io_addr; ++ u32 hw_inst; + + struct { +- enum aspeed_kcs_irq_mode mode; +- int id; +- } upstream_irq; ++ u32 id; ++ u32 type; ++ } sirq; + + struct { + spinlock_t lock; +@@ -127,6 +114,13 @@ + } obe; + }; + ++static const struct kcs_ioreg aspeed_kcs_ioregs[KCS_HW_INSTANCE_NUM] = { ++ { .idr = IDR1, .odr = ODR1, .str = STR1 }, ++ { .idr = IDR2, .odr = ODR2, .str = STR2 }, ++ { .idr = IDR3, .odr = ODR3, .str = STR3 }, ++ { .idr = IDR4, .odr = ODR4, .str = STR4 }, ++}; ++ + static inline struct aspeed_kcs_bmc *to_aspeed_kcs_bmc(struct kcs_bmc_device *kcs_bmc) + { + return container_of(kcs_bmc, struct aspeed_kcs_bmc, kcs_bmc); +@@ -134,11 +128,11 @@ + + static u8 aspeed_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg) + { +- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); ++ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); + u32 val = 0; + int rc; + +- rc = regmap_read(priv->map, reg, &val); ++ rc = regmap_read(kcs_aspeed->map, reg, &val); + WARN(rc != 0, "regmap_read() failed: %d\n", rc); + + return rc == 0 ? (u8) val : 0; +@@ -146,50 +140,50 @@ + + static void aspeed_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data) + { +- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); ++ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); + int rc; + +- rc = regmap_write(priv->map, reg, data); ++ rc = regmap_write(kcs_aspeed->map, reg, data); + WARN(rc != 0, "regmap_write() failed: %d\n", rc); + + /* Trigger the upstream IRQ on ODR writes, if enabled */ + + switch (reg) { +- case LPC_ODR1: +- case LPC_ODR2: +- case LPC_ODR3: +- case LPC_ODR4: ++ case ODR1: ++ case ODR2: ++ case ODR3: ++ case ODR4: + break; + default: + return; + } + +- if (priv->upstream_irq.mode != aspeed_kcs_irq_serirq) ++ if (kcs_aspeed->sirq.type == IRQ_TYPE_NONE) + return; + +- switch (kcs_bmc->channel) { +- case 1: +- switch (priv->upstream_irq.id) { ++ switch (kcs_aspeed->hw_inst) { ++ case 0: ++ switch (kcs_aspeed->sirq.id) { + case 12: +- regmap_update_bits(priv->map, LPC_SIRQCR0, LPC_SIRQCR0_IRQ12E1, +- LPC_SIRQCR0_IRQ12E1); ++ regmap_update_bits(kcs_aspeed->map, SIRQCR0, SIRQCR0_IRQ12E1, ++ SIRQCR0_IRQ12E1); + break; + case 1: +- regmap_update_bits(priv->map, LPC_SIRQCR0, LPC_SIRQCR0_IRQ1E1, +- LPC_SIRQCR0_IRQ1E1); ++ regmap_update_bits(kcs_aspeed->map, SIRQCR0, SIRQCR0_IRQ1E1, ++ SIRQCR0_IRQ1E1); + break; + default: + break; + } + break; ++ case 1: ++ regmap_update_bits(kcs_aspeed->map, HICR5, HICR5_IRQXE2, HICR5_IRQXE2); ++ break; + case 2: +- regmap_update_bits(priv->map, LPC_HICR5, LPC_HICR5_IRQXE2, LPC_HICR5_IRQXE2); ++ regmap_update_bits(kcs_aspeed->map, HICR5, HICR5_IRQXE3, HICR5_IRQXE3); + break; + case 3: +- regmap_update_bits(priv->map, LPC_HICR5, LPC_HICR5_IRQXE3, LPC_HICR5_IRQXE3); +- break; +- case 4: +- regmap_update_bits(priv->map, LPC_HICRC, LPC_HICRC_IRQXE4, LPC_HICRC_IRQXE4); ++ regmap_update_bits(kcs_aspeed->map, HICRC, HICRC_IRQXE4, HICRC_IRQXE4); + break; + default: + break; +@@ -198,86 +192,116 @@ + + static void aspeed_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 val) + { +- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); ++ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); + int rc; + +- rc = regmap_update_bits(priv->map, reg, mask, val); ++ rc = regmap_update_bits(kcs_aspeed->map, reg, mask, val); + WARN(rc != 0, "regmap_update_bits() failed: %d\n", rc); + } + ++static void aspeed_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state) ++{ ++ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); ++ int rc; ++ u8 str; ++ ++ /* We don't have an OBE IRQ, emulate it */ ++ if (mask & KCS_BMC_EVENT_TYPE_OBE) { ++ if (KCS_BMC_EVENT_TYPE_OBE & state) { ++ /* ++ * Given we don't have an OBE IRQ, delay by polling briefly to see if we can ++ * observe such an event before returning to the caller. This is not ++ * incorrect because OBF may have already become clear before enabling the ++ * IRQ if we had one, under which circumstance no event will be propagated ++ * anyway. ++ * ++ * The onus is on the client to perform a race-free check that it hasn't ++ * missed the event. ++ */ ++ rc = read_poll_timeout_atomic(aspeed_kcs_inb, str, ++ !(str & KCS_BMC_STR_OBF), 1, 100, false, ++ &kcs_aspeed->kcs_bmc, kcs_aspeed->kcs_bmc.ioreg.str); ++ /* Time for the slow path? */ ++ if (rc == -ETIMEDOUT) ++ mod_timer(&kcs_aspeed->obe.timer, jiffies + KCS_OBE_POLL_PERIOD); ++ } else { ++ del_timer(&kcs_aspeed->obe.timer); ++ } ++ } ++ ++ if (mask & KCS_BMC_EVENT_TYPE_IBF) { ++ const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF); ++ ++ switch (kcs_aspeed->hw_inst) { ++ case 0: ++ regmap_update_bits(kcs_aspeed->map, HICR2, HICR2_IBFIE1, ++ enable * HICR2_IBFIE1); ++ return; ++ case 1: ++ regmap_update_bits(kcs_aspeed->map, HICR2, HICR2_IBFIE2, ++ enable * HICR2_IBFIE2); ++ return; ++ case 2: ++ regmap_update_bits(kcs_aspeed->map, HICR2, HICR2_IBFIE3, ++ enable * HICR2_IBFIE3); ++ return; ++ case 3: ++ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_IBFIE4, ++ enable * HICRB_IBFIE4); ++ return; ++ default: ++ pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel); ++ return; ++ } ++ } ++} ++ ++static const struct kcs_bmc_device_ops aspeed_kcs_ops = { ++ .io_inputb = aspeed_kcs_inb, ++ .io_outputb = aspeed_kcs_outb, ++ .io_updateb = aspeed_kcs_updateb, ++ .irq_mask_update = aspeed_kcs_irq_mask_update, ++}; ++ + /* +- * We note D for Data, and C for Cmd/Status, default rules are ++ * Follow IPMI v2.0, given a KCS IO base X, ++ * the Data and Cmd/Status IO addresses are X and X+1. + * +- * 1. Only the D address is given: +- * A. KCS1/KCS2 (D/C: X/X+4) +- * D/C: CA0h/CA4h +- * D/C: CA8h/CACh +- * B. KCS3 (D/C: XX2/XX3h) +- * D/C: CA2h/CA3h +- * C. KCS4 (D/C: X/X+1) +- * D/C: CA4h/CA5h +- * +- * 2. Both the D/C addresses are given: +- * A. KCS1/KCS2/KCS4 (D/C: X/Y) +- * D/C: CA0h/CA1h +- * D/C: CA8h/CA9h +- * D/C: CA4h/CA5h +- * B. KCS3 (D/C: XX2/XX3h) +- * D/C: CA2h/CA3h ++ * Note that the IO base of KCS channel 3/7/11/... must ends with 2 ++ * e.g. CA2h for KCS#3 + */ +-static int aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u32 addrs[2], int nr_addrs) ++static int aspeed_kcs_config_io_address(struct aspeed_kcs_bmc *kcs_aspeed) + { +- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); ++ u32 io_addr; + +- if (WARN_ON(nr_addrs < 1 || nr_addrs > 2)) +- return -EINVAL; ++ io_addr = kcs_aspeed->io_addr; + +- switch (priv->kcs_bmc.channel) { ++ switch (kcs_aspeed->hw_inst) { ++ case 0: ++ regmap_update_bits(kcs_aspeed->map, HICR4, HICR4_LADR12AS, 0); ++ regmap_write(kcs_aspeed->map, LADR12H, io_addr >> 8); ++ regmap_write(kcs_aspeed->map, LADR12L, io_addr & 0xFF); ++ regmap_update_bits(kcs_aspeed->map, LSADR12, LSADR12_LSADR1, ++ FIELD_PREP(LSADR12_LSADR1, io_addr + 1)); ++ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_EN16LADR1, ++ HICRB_EN16LADR1); ++ break; + case 1: +- regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, 0); +- regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8); +- regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF); +- if (nr_addrs == 2) { +- regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR1_MASK, +- addrs[1] << LPC_LSADR12_LSADR1_SHIFT); +- +- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR1, +- LPC_HICRB_EN16LADR1); +- } ++ regmap_update_bits(kcs_aspeed->map, HICR4, HICR4_LADR12AS, HICR4_LADR12AS); ++ regmap_write(kcs_aspeed->map, LADR12H, io_addr >> 8); ++ regmap_write(kcs_aspeed->map, LADR12L, io_addr & 0xFF); ++ regmap_update_bits(kcs_aspeed->map, LSADR12, LSADR12_LSADR2, ++ FIELD_PREP(LSADR12_LSADR2, io_addr + 1)); ++ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_EN16LADR2, ++ HICRB_EN16LADR2); + break; +- + case 2: +- regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS); +- regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8); +- regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF); +- if (nr_addrs == 2) { +- regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR2_MASK, +- addrs[1] << LPC_LSADR12_LSADR2_SHIFT); +- +- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR2, +- LPC_HICRB_EN16LADR2); +- } ++ regmap_write(kcs_aspeed->map, LADR3H, io_addr >> 8); ++ regmap_write(kcs_aspeed->map, LADR3L, io_addr & 0xFF); + break; +- + case 3: +- if (nr_addrs == 2) { +- dev_err(priv->kcs_bmc.dev, +- "Channel 3 only supports inferred status IO address\n"); +- return -EINVAL; +- } +- +- regmap_write(priv->map, LPC_LADR3H, addrs[0] >> 8); +- regmap_write(priv->map, LPC_LADR3L, addrs[0] & 0xFF); ++ regmap_write(kcs_aspeed->map, LADR4, ((io_addr + 1) << 16) | io_addr); + break; +- +- case 4: +- if (nr_addrs == 1) +- regmap_write(priv->map, LPC_LADR4, ((addrs[0] + 1) << 16) | addrs[0]); +- else +- regmap_write(priv->map, LPC_LADR4, (addrs[1] << 16) | addrs[0]); +- +- break; +- + default: + return -EINVAL; + } +@@ -285,398 +309,283 @@ + return 0; + } + +-static inline int aspeed_kcs_map_serirq_type(u32 dt_type) +-{ +- switch (dt_type) { +- case IRQ_TYPE_EDGE_RISING: +- return LPC_TYIRQX_RISING; +- case IRQ_TYPE_LEVEL_HIGH: +- return LPC_TYIRQX_HIGH; +- case IRQ_TYPE_LEVEL_LOW: +- return LPC_TYIRQX_LOW; +- default: +- return -EINVAL; +- } +-} +- +-static int aspeed_kcs_config_upstream_irq(struct aspeed_kcs_bmc *priv, u32 id, u32 dt_type) ++static int aspeed_kcs_config_upstream_serirq(struct aspeed_kcs_bmc *kcs_aspeed) + { +- unsigned int mask, val, hw_type; +- int ret; ++ unsigned int mask, val; ++ u32 sirq_id, sirq_type; + +- if (id > 15) +- return -EINVAL; +- +- ret = aspeed_kcs_map_serirq_type(dt_type); +- if (ret < 0) +- return ret; +- hw_type = ret; ++ if (kcs_aspeed->sirq.type == IRQ_TYPE_NONE) ++ return 0; + +- priv->upstream_irq.mode = aspeed_kcs_irq_serirq; +- priv->upstream_irq.id = id; ++ sirq_id = kcs_aspeed->sirq.id; ++ sirq_type = kcs_aspeed->sirq.type; + +- switch (priv->kcs_bmc.channel) { +- case 1: ++ switch (kcs_aspeed->hw_inst) { ++ case 0: + /* Needs IRQxE1 rather than (ID1IRQX, SEL1IRQX, IRQXE1) before AST2600 A3 */ + break; ++ case 1: ++ mask = HICR5_SEL2IRQX | HICR5_ID2IRQX; ++ val = FIELD_PREP(HICR5_ID2IRQX, sirq_id); ++ val |= (sirq_type == IRQ_TYPE_LEVEL_HIGH) ? HICR5_SEL2IRQX : 0; ++ regmap_update_bits(kcs_aspeed->map, HICR5, mask, val); ++ break; + case 2: +- if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH)) +- return -EINVAL; +- +- mask = LPC_HICR5_SEL2IRQX | LPC_HICR5_ID2IRQX_MASK; +- val = (id << LPC_HICR5_ID2IRQX_SHIFT); +- val |= (hw_type == LPC_TYIRQX_HIGH) ? LPC_HICR5_SEL2IRQX : 0; +- regmap_update_bits(priv->map, LPC_HICR5, mask, val); +- ++ mask = HICR5_SEL3IRQX | HICR5_ID3IRQX; ++ val = FIELD_PREP(HICR5_ID3IRQX, sirq_id); ++ val |= (sirq_type == IRQ_TYPE_LEVEL_HIGH) ? HICR5_SEL3IRQX : 0; ++ regmap_update_bits(kcs_aspeed->map, HICR5, mask, val); + break; + case 3: +- if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH)) +- return -EINVAL; +- +- mask = LPC_HICR5_SEL3IRQX | LPC_HICR5_ID3IRQX_MASK; +- val = (id << LPC_HICR5_ID3IRQX_SHIFT); +- val |= (hw_type == LPC_TYIRQX_HIGH) ? LPC_HICR5_SEL3IRQX : 0; +- regmap_update_bits(priv->map, LPC_HICR5, mask, val); +- +- break; +- case 4: +- mask = LPC_HICRC_ID4IRQX_MASK | LPC_HICRC_TY4IRQX_MASK | LPC_HICRC_OBF4_AUTO_CLR; +- val = (id << LPC_HICRC_ID4IRQX_SHIFT) | (hw_type << LPC_HICRC_TY4IRQX_SHIFT); +- regmap_update_bits(priv->map, LPC_HICRC, mask, val); ++ mask = HICRC_ID4IRQX | HICRC_SEL4IRQX | HICRC_OBF4_AUTO_CLR; ++ val = FIELD_PREP(HICRC_ID4IRQX, sirq_id); ++ val |= (sirq_type == IRQ_TYPE_LEVEL_HIGH) ? HICRC_SEL4IRQX : 0; ++ regmap_update_bits(kcs_aspeed->map, HICRC, mask, val); + break; + default: +- dev_warn(priv->kcs_bmc.dev, ++ dev_warn(kcs_aspeed->kcs_bmc.dev, + "SerIRQ configuration not supported on KCS channel %d\n", +- priv->kcs_bmc.channel); ++ kcs_aspeed->kcs_bmc.channel); + return -EINVAL; + } + return 0; } @@ -23721,45 +23656,9 @@ diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspe MODULE_AUTHOR("Andrew Jeffery "); +MODULE_AUTHOR("Chia-Wei Wang "); MODULE_DESCRIPTION("Aspeed device interface to the KCS BMC device"); -diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig ---- a/drivers/clk/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/clk/Kconfig 2025-12-23 10:16:07.639258736 +0000 -@@ -277,6 +277,20 @@ - The G4 and G5 series, including the ast2400 and ast2500, are supported - by this driver. - -+config COMMON_CLK_AST2700 -+ bool "Clock driver for AST2700 SoC" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ help -+ This driver provides support for clock on AST2700 SoC. -+ The driver is responsible for managing the various clocks required -+ by the peripherals and cores within the AST2700. -+ -+config COMMON_CLK_AST1700 -+ bool "Clock driver for AST1700" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ help -+ This driver supports the AST1700 clocks on the Aspeed BMC platforms. -+ - config COMMON_CLK_S2MPS11 - tristate "Clock driver for S2MPS1X/S5M8767 MFD" - depends on MFD_SEC_CORE || COMPILE_TEST -diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile ---- a/drivers/clk/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/clk/Makefile 2025-12-23 10:16:11.218198718 +0000 -@@ -48,6 +48,8 @@ - obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o - obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o - obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o -+obj-$(CONFIG_COMMON_CLK_AST2700) += clk-ast2700.o -+obj-$(CONFIG_COMMON_CLK_AST1700) += clk-ast1700.o - obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o - obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o - obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c ---- a/drivers/clk/clk-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/clk/clk-aspeed.c 2025-12-23 10:16:20.650040614 +0000 +--- a/drivers/clk/clk-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/clk/clk-aspeed.c 2026-09-09 15:51:44.114247198 +0000 @@ -54,15 +54,15 @@ [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, CLK_IS_CRITICAL }, /* DAC */ [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL }, @@ -23790,8 +23689,8 @@ diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c * SCUD4 resets start at an offset to separate them from diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c --- a/drivers/clk/clk-ast1700.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/clk/clk-ast1700.c 2025-12-23 10:16:20.655040530 +0000 -@@ -0,0 +1,807 @@ ++++ b/drivers/clk/clk-ast1700.c 2026-09-09 15:51:44.119247123 +0000 +@@ -0,0 +1,809 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright ASPEED Technology + @@ -23819,6 +23718,8 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c +#define AST1700_UXCLK_CTRL 0x330 +#define AST1700_HUXCLK_CTRL 0x334 + ++#define CREATE_CLK_NAME(id, suffix) kasprintf(GFP_KERNEL, "ast1700_%d-%s", id, suffix) ++ +static DEFINE_IDA(ast1700_clk_ida); + +/* Globally visible clocks */ @@ -23876,7 +23777,7 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c + { 0 } +}; + -+static struct clk_hw *AST1700_calc_uclk(const char *name, u32 val) ++static struct clk_hw *AST1700_calc_uclk(int id, u32 val) +{ + unsigned int mult, div; + @@ -23887,10 +23788,11 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c + mult = r; + div = n * 2; + -+ return clk_hw_register_fixed_factor(NULL, name, "ast1700-uxclk", 0, mult, div); ++ return clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "uartxclk"), ++ CREATE_CLK_NAME(id, "uxclk"), 0, mult, div); +}; + -+static struct clk_hw *AST1700_calc_huclk(const char *name, u32 val) ++static struct clk_hw *AST1700_calc_huclk(int id, u32 val) +{ + unsigned int mult, div; + @@ -23901,7 +23803,8 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c + mult = r; + div = n * 2; + -+ return clk_hw_register_fixed_factor(NULL, name, "ast1700-huxclk", 0, mult, div); ++ return clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "huartxclk"), ++ CREATE_CLK_NAME(id, "huxclk"), 0, mult, div); +}; + +static struct clk_hw *AST1700_calc_pll(const char *name, const char *parent_name, u32 val) @@ -24074,8 +23977,6 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c + "ast1700_1-hpll", +}; + -+#define CREATE_CLK_NAME(id, suffix) kasprintf(GFP_KERNEL, "ast1700_%d-%s", id, suffix) -+ +static int AST1700_clk_init(struct device_node *ast1700_node) +{ + struct clk_hw_onecell_data *clk_data; @@ -24156,7 +24057,7 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c + 0, 2, 0, &ast1700_clk_lock); + + val = readl(clk_base + AST1700_UXCLK_CTRL); -+ clks[AST1700_CLK_UARTX] = AST1700_calc_uclk(CREATE_CLK_NAME(id, "uartxclk"), val); ++ clks[AST1700_CLK_UARTX] = AST1700_calc_uclk(id, val); + + /* huxclk mux selection */ + clks[AST1700_CLK_HUXCLK] = @@ -24167,7 +24068,7 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c + 3, 2, 0, &ast1700_clk_lock); + + val = readl(clk_base + AST1700_HUXCLK_CTRL); -+ clks[AST1700_CLK_HUARTX] = AST1700_calc_huclk(CREATE_CLK_NAME(id, "huartxclk"), val); ++ clks[AST1700_CLK_HUARTX] = AST1700_calc_huclk(id, val); + + /* AHB CLK = 200Mhz */ + clks[AST1700_CLK_AHB] = @@ -24600,8 +24501,8 @@ diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c +CLK_OF_DECLARE_DRIVER(ast1700, "aspeed,ast1700-scu", AST1700_clk_init); + diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c ---- a/drivers/clk/clk-ast2600.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/clk/clk-ast2600.c 2025-12-23 10:16:20.661040429 +0000 +--- a/drivers/clk/clk-ast2600.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/clk/clk-ast2600.c 2026-09-09 15:51:44.126247017 +0000 @@ -19,7 +19,7 @@ * This includes the gates (configured from aspeed_g6_gates), plus the * explicitly-configured clocks (ASPEED_CLK_HPLL and up). @@ -24611,32 +24512,21 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c #define ASPEED_G6_SILICON_REV 0x014 #define CHIP_REVISION_ID GENMASK(23, 16) -@@ -59,8 +59,24 @@ +@@ -59,9 +59,13 @@ #define ASPEED_G6_STRAP1 0x500 +#define ASPEED_UARTCLK_FROM_UXCLK 0x338 + #define ASPEED_MAC12_CLK_DLY 0x340 -+#define ASPEED_MAC12_CLK_DLY_100M 0x348 -+#define ASPEED_MAC12_CLK_DLY_10M 0x34C -+ #define ASPEED_MAC34_CLK_DLY 0x350 -+#define ASPEED_MAC34_CLK_DLY_100M 0x358 -+#define ASPEED_MAC34_CLK_DLY_10M 0x35C -+ + +#define ASPEED_G6_MAC34_DRIVING_CTRL 0x458 + -+#define ASPEED_G6_DEF_MAC12_DELAY_1G 0x0028a410 -+#define ASPEED_G6_DEF_MAC12_DELAY_100M 0x00410410 -+#define ASPEED_G6_DEF_MAC12_DELAY_10M 0x00410410 -+#define ASPEED_G6_DEF_MAC34_DELAY_1G 0x00104208 -+#define ASPEED_G6_DEF_MAC34_DELAY_100M 0x00104208 -+#define ASPEED_G6_DEF_MAC34_DELAY_10M 0x00104208 - /* Globally visible clocks */ static DEFINE_SPINLOCK(aspeed_g6_clk_lock); -@@ -72,6 +88,45 @@ + +@@ -72,6 +76,45 @@ /* AST2600 revision: A0, A1, A2, etc */ static u8 soc_rev; @@ -24682,7 +24572,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c /* * The majority of the clocks in the system are gates paired with a reset * controller that holds the IP in reset; this is represented by the @reset_idx -@@ -99,14 +154,14 @@ +@@ -99,14 +142,14 @@ * ref0 and ref1 are essential for the SoC to operate * mpll is required if SDRAM is used */ @@ -24699,7 +24589,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c /* From dpll */ [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, CLK_IS_CRITICAL }, /* DAC */ [ASPEED_CLK_GATE_REF0CLK] = { 6, -1, "ref0clk-gate", "clkin", CLK_IS_CRITICAL }, -@@ -128,8 +183,8 @@ +@@ -128,8 +171,8 @@ /* Reserved 26 */ [ASPEED_CLK_GATE_EMMCCLK] = { 27, 16, "emmcclk-gate", NULL, 0 }, /* For card clk */ /* Reserved 28/29/30 */ @@ -24710,7 +24600,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c [ASPEED_CLK_GATE_REF1CLK] = { 34, -1, "ref1clk-gate", "clkin", CLK_IS_CRITICAL }, /* Reserved 35 */ [ASPEED_CLK_GATE_SDCLK] = { 36, 56, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ -@@ -143,20 +198,20 @@ +@@ -143,20 +186,20 @@ [ASPEED_CLK_GATE_I3C4CLK] = { 44, 44, "i3c4clk-gate", "i3cclk", 0 }, /* I3C4 */ [ASPEED_CLK_GATE_I3C5CLK] = { 45, 45, "i3c5clk-gate", "i3cclk", 0 }, /* I3C5 */ /* Reserved: 46 & 47 */ @@ -24743,7 +24633,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", "fsiclk", 0 }, /* FSI */ }; -@@ -184,6 +239,18 @@ +@@ -184,6 +227,18 @@ { 0 } }; @@ -24762,7 +24652,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c static const struct clk_div_table ast2600_mac_div_table[] = { { 0x0, 4 }, { 0x1, 4 }, -@@ -384,9 +451,14 @@ +@@ -384,9 +439,14 @@ struct aspeed_reset *ar = to_aspeed_reset(rcdev); u32 rst = get_bit(id); u32 reg = id >= 32 ? ASPEED_G6_RESET_CTRL2 : ASPEED_G6_RESET_CTRL; @@ -24778,7 +24668,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c } static int aspeed_g6_reset_assert(struct reset_controller_dev *rcdev, -@@ -458,11 +530,6 @@ +@@ -458,11 +518,6 @@ return hw; } @@ -24790,7 +24680,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c static const char * const vclk_parent_names[] = { "dpll", "d1pll", -@@ -484,7 +551,7 @@ +@@ -484,7 +539,7 @@ struct aspeed_reset *ar; struct regmap *map; struct clk_hw *hw; @@ -24799,7 +24689,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c int i, ret; map = syscon_node_to_regmap(dev->of_node); -@@ -510,70 +577,50 @@ +@@ -510,70 +565,50 @@ return ret; } @@ -24824,13 +24714,18 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c - if (IS_ERR(hw)) - return PTR_ERR(hw); - aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = hw; -- ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(14, 11), BIT(11)); + - /* EMMC ext clock */ - hw = clk_hw_register_fixed_factor(dev, "emmc_extclk_hpll_in", "hpll", - 0, 1, 2); -- if (IS_ERR(hw)) -- return PTR_ERR(hw); -- ++ /* EMMC ext clock divider */ ++ hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "mpll", 0, ++ scu_g6_base + ASPEED_G6_CLK_SELECTION1, 15, 0, ++ &aspeed_g6_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + - hw = clk_hw_register_mux(dev, "emmc_extclk_mux", - emmc_extclk_parent_names, - ARRAY_SIZE(emmc_extclk_parent_names), 0, @@ -24838,18 +24733,13 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c - 0, &aspeed_g6_clk_lock); - if (IS_ERR(hw)) - return PTR_ERR(hw); -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(14, 11), BIT(11)); - +- - hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "emmc_extclk_mux", - 0, scu_g6_base + ASPEED_G6_CLK_SELECTION1, - 15, 0, &aspeed_g6_clk_lock); -+ /* EMMC ext clock divider */ -+ hw = clk_hw_register_gate(dev, "emmc_extclk_gate", "mpll", 0, -+ scu_g6_base + ASPEED_G6_CLK_SELECTION1, 15, 0, -+ &aspeed_g6_clk_lock); - if (IS_ERR(hw)) - return PTR_ERR(hw); - +- if (IS_ERR(hw)) +- return PTR_ERR(hw); +- - hw = clk_hw_register_divider_table(dev, "emmc_extclk", - "emmc_extclk_gate", 0, - scu_g6_base + @@ -24902,7 +24792,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c aspeed_g6_clk_data->hws[ASPEED_CLK_SDIO] = hw; /* MAC1/2 RMII 50MHz RCLK */ -@@ -645,8 +692,8 @@ +@@ -645,8 +680,8 @@ return PTR_ERR(hw); aspeed_g6_clk_data->hws[ASPEED_CLK_LHCLK] = hw; @@ -24913,7 +24803,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c /* SoC Display clock selection */ hw = clk_hw_register_mux(dev, "d1clk", d1clk_parent_names, ARRAY_SIZE(d1clk_parent_names), 0, -@@ -677,6 +724,8 @@ +@@ -677,6 +712,8 @@ return PTR_ERR(hw); aspeed_g6_clk_data->hws[ASPEED_CLK_VCLK] = hw; @@ -24922,7 +24812,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c /* Video Engine clock divider */ hw = clk_hw_register_divider_table(dev, "eclk", NULL, 0, scu_g6_base + ASPEED_G6_CLK_SELECTION1, 28, 3, 0, -@@ -686,6 +735,26 @@ +@@ -686,6 +723,26 @@ return PTR_ERR(hw); aspeed_g6_clk_data->hws[ASPEED_CLK_ECLK] = hw; @@ -24949,7 +24839,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c for (i = 0; i < ARRAY_SIZE(aspeed_g6_gates); i++) { const struct aspeed_gate_data *gd = &aspeed_g6_gates[i]; u32 gate_flags; -@@ -749,7 +818,8 @@ +@@ -749,7 +806,8 @@ static void __init aspeed_g6_cc(struct regmap *map) { struct clk_hw *hw; @@ -24959,7 +24849,7 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000); -@@ -814,6 +884,55 @@ +@@ -814,6 +872,55 @@ hw = clk_hw_register_fixed_rate(NULL, "usb-phy-40m", NULL, 0, 40000000); aspeed_g6_clk_data->hws[ASPEED_CLK_USBPHY_40M] = hw; @@ -25015,18 +24905,15 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c /* i3c clock: source from apll, divide by 8 */ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION5, I3C_CLK_SELECTION | APLL_DIV_SELECTION, -@@ -829,6 +948,10 @@ +@@ -829,6 +936,7 @@ static void __init aspeed_g6_cc_init(struct device_node *np) { struct regmap *map; -+ struct mac_delay_config mac_cfg; -+ union mac_delay_1g reg_1g; -+ union mac_delay_100_10 reg_100, reg_10; + u32 uart_clk_source = 0; int ret; int i; -@@ -863,6 +986,100 @@ +@@ -863,6 +971,32 @@ return; } @@ -25049,77 +24936,9 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c + regmap_update_bits(map, ASPEED_G6_CLK_SELECTION4, GENMASK(18, 16), + (0x3 << 16)); + -+ /* BIT[31]: MAC1/2 RGMII 125M source = internal PLL -+ * BIT[28]: RGMIICK pad direction = output -+ */ -+ regmap_write(map, ASPEED_MAC12_CLK_DLY, -+ BIT(31) | BIT(28) | ASPEED_G6_DEF_MAC12_DELAY_1G); -+ regmap_write(map, ASPEED_MAC12_CLK_DLY_100M, -+ ASPEED_G6_DEF_MAC12_DELAY_100M); -+ regmap_write(map, ASPEED_MAC12_CLK_DLY_10M, -+ ASPEED_G6_DEF_MAC12_DELAY_10M); -+ -+ /* MAC3/4 RGMII 125M source = RGMIICK pad */ -+ regmap_write(map, ASPEED_MAC34_CLK_DLY, -+ ASPEED_G6_DEF_MAC34_DELAY_1G); -+ regmap_write(map, ASPEED_MAC34_CLK_DLY_100M, -+ ASPEED_G6_DEF_MAC34_DELAY_100M); -+ regmap_write(map, ASPEED_MAC34_CLK_DLY_10M, -+ ASPEED_G6_DEF_MAC34_DELAY_10M); -+ + /* MAC3/4 default pad driving strength */ + regmap_write(map, ASPEED_G6_MAC34_DRIVING_CTRL, 0x0000000f); + -+ regmap_read(map, ASPEED_MAC12_CLK_DLY, ®_1g.w); -+ regmap_read(map, ASPEED_MAC12_CLK_DLY_100M, ®_100.w); -+ regmap_read(map, ASPEED_MAC12_CLK_DLY_10M, ®_10.w); -+ ret = of_property_read_u32_array(np, "mac0-clk-delay", (u32 *)&mac_cfg, 6); -+ if (!ret) { -+ reg_1g.b.tx_delay_1 = mac_cfg.tx_delay_1000; -+ reg_1g.b.rx_delay_1 = mac_cfg.rx_delay_1000; -+ reg_100.b.tx_delay_1 = mac_cfg.tx_delay_100; -+ reg_100.b.rx_delay_1 = mac_cfg.rx_delay_100; -+ reg_10.b.tx_delay_1 = mac_cfg.tx_delay_10; -+ reg_10.b.rx_delay_1 = mac_cfg.rx_delay_10; -+ } -+ ret = of_property_read_u32_array(np, "mac1-clk-delay", (u32 *)&mac_cfg, 6); -+ if (!ret) { -+ reg_1g.b.tx_delay_2 = mac_cfg.tx_delay_1000; -+ reg_1g.b.rx_delay_2 = mac_cfg.rx_delay_1000; -+ reg_100.b.tx_delay_2 = mac_cfg.tx_delay_100; -+ reg_100.b.rx_delay_2 = mac_cfg.rx_delay_100; -+ reg_10.b.tx_delay_2 = mac_cfg.tx_delay_10; -+ reg_10.b.rx_delay_2 = mac_cfg.rx_delay_10; -+ } -+ regmap_write(map, ASPEED_MAC12_CLK_DLY, reg_1g.w); -+ regmap_write(map, ASPEED_MAC12_CLK_DLY_100M, reg_100.w); -+ regmap_write(map, ASPEED_MAC12_CLK_DLY_10M, reg_10.w); -+ -+ regmap_read(map, ASPEED_MAC34_CLK_DLY, ®_1g.w); -+ regmap_read(map, ASPEED_MAC34_CLK_DLY_100M, ®_100.w); -+ regmap_read(map, ASPEED_MAC34_CLK_DLY_10M, ®_10.w); -+ ret = of_property_read_u32_array(np, "mac2-clk-delay", (u32 *)&mac_cfg, 6); -+ if (!ret) { -+ reg_1g.b.tx_delay_1 = mac_cfg.tx_delay_1000; -+ reg_1g.b.rx_delay_1 = mac_cfg.rx_delay_1000; -+ reg_100.b.tx_delay_1 = mac_cfg.tx_delay_100; -+ reg_100.b.rx_delay_1 = mac_cfg.rx_delay_100; -+ reg_10.b.tx_delay_1 = mac_cfg.tx_delay_10; -+ reg_10.b.rx_delay_1 = mac_cfg.rx_delay_10; -+ } -+ ret = of_property_read_u32_array(np, "mac3-clk-delay", (u32 *)&mac_cfg, 6); -+ if (!ret) { -+ reg_1g.b.tx_delay_2 = mac_cfg.tx_delay_1000; -+ reg_1g.b.rx_delay_2 = mac_cfg.rx_delay_1000; -+ reg_100.b.tx_delay_2 = mac_cfg.tx_delay_100; -+ reg_100.b.rx_delay_2 = mac_cfg.rx_delay_100; -+ reg_10.b.tx_delay_2 = mac_cfg.tx_delay_10; -+ reg_10.b.rx_delay_2 = mac_cfg.rx_delay_10; -+ } -+ regmap_write(map, ASPEED_MAC34_CLK_DLY, reg_1g.w); -+ regmap_write(map, ASPEED_MAC34_CLK_DLY_100M, reg_100.w); -+ regmap_write(map, ASPEED_MAC34_CLK_DLY_10M, reg_10.w); -+ + /* A0/A1 need change to RSA clock = HPLL/3, A2/A3 have been set at Rom Code */ + regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, BIT(19), BIT(19)); + regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(27, 26), (2 << 26)); @@ -25129,8 +24948,8 @@ diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c if (ret) diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c --- a/drivers/clk/clk-ast2700.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/clk/clk-ast2700.c 2025-12-23 10:16:20.644040714 +0000 -@@ -0,0 +1,1334 @@ ++++ b/drivers/clk/clk-ast2700.c 2026-09-09 15:51:44.107247304 +0000 +@@ -0,0 +1,1254 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 ASPEED Technology Inc. @@ -25180,39 +24999,6 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c +#define SCU1_UXCLK_CTRL 0x330 +#define SCU1_HUXCLK_CTRL 0x334 +#define SCU1_MAC12_CLK_DLY 0x390 -+#define SCU1_MAC12_CLK_DLY_100M 0x394 -+#define SCU1_MAC12_CLK_DLY_10M 0x398 -+ -+/* -+ * MAC Clock Delay settings -+ */ -+#define MAC_CLK_RMII1_50M_RCLK_O_CTRL BIT(30) -+#define MAC_CLK_RMII1_50M_RCLK_O_DIS 0 -+#define MAC_CLK_RMII1_50M_RCLK_O_EN 1 -+#define MAC_CLK_RMII0_50M_RCLK_O_CTRL BIT(29) -+#define MAC_CLK_RMII0_5M_RCLK_O_DIS 0 -+#define MAC_CLK_RMII0_5M_RCLK_O_EN 1 -+#define MAC_CLK_RMII_TXD_FALLING_2 BIT(27) -+#define MAC_CLK_RMII_TXD_FALLING_1 BIT(26) -+#define MAC_CLK_RXCLK_INV_2 BIT(25) -+#define MAC_CLK_RXCLK_INV_1 BIT(24) -+#define MAC_CLK_1G_INPUT_DELAY_2 GENMASK(23, 18) -+#define MAC_CLK_1G_INPUT_DELAY_1 GENMASK(17, 12) -+#define MAC_CLK_1G_OUTPUT_DELAY_2 GENMASK(11, 6) -+#define MAC_CLK_1G_OUTPUT_DELAY_1 GENMASK(5, 0) -+ -+#define MAC_CLK_100M_10M_RESERVED GENMASK(31, 26) -+#define MAC_CLK_100M_10M_RXCLK_INV_2 BIT(25) -+#define MAC_CLK_100M_10M_RXCLK_INV_1 BIT(24) -+#define MAC_CLK_100M_10M_INPUT_DELAY_2 GENMASK(23, 18) -+#define MAC_CLK_100M_10M_INPUT_DELAY_1 GENMASK(17, 12) -+#define MAC_CLK_100M_10M_OUTPUT_DELAY_2 GENMASK(11, 6) -+#define MAC_CLK_100M_10M_OUTPUT_DELAY_1 GENMASK(5, 0) -+ -+#define AST2700_DEF_MAC12_DELAY_1G_A0 0x00CF4D75 -+#define AST2700_DEF_MAC12_DELAY_1G_A1 0x005D6618 -+#define AST2700_DEF_MAC12_DELAY_100M 0x00410410 -+#define AST2700_DEF_MAC12_DELAY_10M 0x00410410 + +struct mac_delay_config { + u32 tx_delay_1000; @@ -25446,6 +25232,13 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c + +static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)]; + ++static const unsigned int peciclk_parent_ids[] = { ++ SCU1_CLKIN, ++ SCU1_CLK_HPLL_DIV4 ++}; ++ ++static const struct clk_hw *peciclk_parent_hws[ARRAY_SIZE(peciclk_parent_ids)]; ++ +#define FIXED_CLK(_id, _name, _rate) \ + { \ + .id = _id, \ @@ -25631,6 +25424,7 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c + PLL_CLK(SCU1_CLK_HPLL, CLK_PLL, "soc1-hpll", SCU1_CLKIN, SCU1_HPLL_PARAM), + PLL_CLK(SCU1_CLK_APLL, CLK_PLL, "soc1-apll", SCU1_CLKIN, SCU1_APLL_PARAM), + PLL_CLK(SCU1_CLK_DPLL, CLK_PLL, "soc1-dpll", SCU1_CLKIN, SCU1_DPLL_PARAM), ++ FIXED_FACTOR_CLK(SCU1_CLK_HPLL_DIV4, "soc1-hpll_div4", SCU1_CLK_HPLL, 1, 4), + FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV2, "soc1-apll_div2", SCU1_CLK_APLL, 1, 2), + FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV4, "soc1-apll_div4", SCU1_CLK_APLL, 1, 4), + FIXED_FACTOR_CLK(SCU1_CLK_CAN, "canclk", SCU1_CLK_APLL, 1, 10), @@ -25654,6 +25448,8 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c + uxclk_parent_hws, SCU1_CLK_SEL2, 0, 2), + MUX_CLK(SCU1_CLK_HUXCLK, "huxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids), + uxclk_parent_hws, SCU1_CLK_SEL2, 3, 2), ++ MUX_CLK(SCU1_CLK_PECI, "peciclk", peciclk_parent_ids, ARRAY_SIZE(peciclk_parent_ids), ++ peciclk_parent_hws, SCU1_CLK_SEL2, 16, 1), + DIVIDER_CLK(SCU1_CLK_SDCLK, "sdclk", SCU1_CLK_SDMUX, + SCU1_CLK_SEL1, 14, 3, ast2700_clk_div_table), + PLL_CLK(SCU1_CLK_UARTX, CLK_UART_PLL, "uartxclk", SCU1_CLK_UXCLK, SCU1_UXCLK_CTRL), @@ -26187,62 +25983,6 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c + return hw; +} + -+static void ast2700_soc1_configure_mac01_clk(struct ast2700_clk_ctrl *clk_ctrl) -+{ -+ struct device_node *np = clk_ctrl->dev->of_node; -+ struct mac_delay_config mac_cfg; -+ u32 reg[3]; -+ int ret; -+ -+ if (readl(clk_ctrl->base) & REVISION_ID) { -+ if ((readl(clk_ctrl->base + SCU1_MAC12_CLK_DLY) & GENMASK(25, 0)) == 0) -+ reg[0] = AST2700_DEF_MAC12_DELAY_1G_A1; -+ else -+ reg[0] = readl(clk_ctrl->base + SCU1_MAC12_CLK_DLY); -+ } else { -+ reg[0] = AST2700_DEF_MAC12_DELAY_1G_A0; -+ } -+ reg[1] = AST2700_DEF_MAC12_DELAY_100M; -+ reg[2] = AST2700_DEF_MAC12_DELAY_10M; -+ -+ ret = of_property_read_u32_array(np, "mac0-clk-delay", (u32 *)&mac_cfg, -+ sizeof(mac_cfg) / sizeof(u32)); -+ if (!ret) { -+ reg[0] &= ~(MAC_CLK_1G_INPUT_DELAY_1 | MAC_CLK_1G_OUTPUT_DELAY_1); -+ reg[0] |= FIELD_PREP(MAC_CLK_1G_INPUT_DELAY_1, mac_cfg.rx_delay_1000) | -+ FIELD_PREP(MAC_CLK_1G_OUTPUT_DELAY_1, mac_cfg.tx_delay_1000); -+ -+ reg[1] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_1 | MAC_CLK_100M_10M_OUTPUT_DELAY_1); -+ reg[1] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_1, mac_cfg.rx_delay_100) | -+ FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_1, mac_cfg.tx_delay_100); -+ -+ reg[2] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_1 | MAC_CLK_100M_10M_OUTPUT_DELAY_1); -+ reg[2] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_1, mac_cfg.rx_delay_10) | -+ FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_1, mac_cfg.tx_delay_10); -+ } -+ -+ ret = of_property_read_u32_array(np, "mac1-clk-delay", (u32 *)&mac_cfg, -+ sizeof(mac_cfg) / sizeof(u32)); -+ if (!ret) { -+ reg[0] &= ~(MAC_CLK_1G_INPUT_DELAY_2 | MAC_CLK_1G_OUTPUT_DELAY_2); -+ reg[0] |= FIELD_PREP(MAC_CLK_1G_INPUT_DELAY_2, mac_cfg.rx_delay_1000) | -+ FIELD_PREP(MAC_CLK_1G_OUTPUT_DELAY_2, mac_cfg.tx_delay_1000); -+ -+ reg[1] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_2 | MAC_CLK_100M_10M_OUTPUT_DELAY_2); -+ reg[1] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_2, mac_cfg.rx_delay_100) | -+ FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_2, mac_cfg.tx_delay_100); -+ -+ reg[2] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_2 | MAC_CLK_100M_10M_OUTPUT_DELAY_2); -+ reg[2] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_2, mac_cfg.rx_delay_10) | -+ FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_2, mac_cfg.tx_delay_10); -+ } -+ -+ reg[0] |= (readl(clk_ctrl->base + SCU1_MAC12_CLK_DLY) & ~GENMASK(25, 0)); -+ writel(reg[0], clk_ctrl->base + SCU1_MAC12_CLK_DLY); -+ writel(reg[1], clk_ctrl->base + SCU1_MAC12_CLK_DLY_100M); -+ writel(reg[2], clk_ctrl->base + SCU1_MAC12_CLK_DLY_10M); -+} -+ +static void ast2700_soc1_configure_i3c_clk(struct ast2700_clk_ctrl *clk_ctrl) +{ + if (readl(clk_ctrl->base) & REVISION_ID) { @@ -26314,7 +26054,6 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c + writel(val | uart_clk_source, clk_base + SCU1_CLK_SEL1); + } + -+ ast2700_soc1_configure_mac01_clk(clk_ctrl); + ast2700_soc1_configure_i3c_clk(clk_ctrl); + } + @@ -26466,8 +26205,8 @@ diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c +} +arch_initcall(clk_ast2700_init); diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig ---- a/drivers/crypto/aspeed/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/Kconfig 2025-12-23 10:16:21.140032401 +0000 +--- a/drivers/crypto/aspeed/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/Kconfig 2026-09-09 15:51:44.737237784 +0000 @@ -1,26 +1,32 @@ config CRYPTO_DEV_ASPEED - tristate "Support for Aspeed cryptographic engine driver" @@ -26508,7 +26247,7 @@ diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig select CRYPTO_SHA1 select CRYPTO_SHA256 select CRYPTO_SHA512 -@@ -33,25 +39,56 @@ +@@ -33,25 +39,55 @@ config CRYPTO_DEV_ASPEED_HACE_CRYPTO bool "Enable Aspeed Hash & Crypto Engine (HACE) crypto" @@ -26518,8 +26257,7 @@ diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig select CRYPTO_DES select CRYPTO_ECB select CRYPTO_CBC -+ select CRYPTO_CFB -+ select CRYPTO_OFB ++ select CRYPTO_GCM select CRYPTO_CTR help Select here to enable Aspeed Hash & Crypto Engine (HACE) @@ -26571,11 +26309,12 @@ diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig + +endif #CRYPTO_DEV_ASPEED diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile ---- a/drivers/crypto/aspeed/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/Makefile 2025-12-23 10:16:21.140032401 +0000 +--- a/drivers/crypto/aspeed/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/Makefile 2026-09-09 15:51:44.737237784 +0000 @@ -1,11 +1,14 @@ hace-hash-$(CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH) := aspeed-hace-hash.o - hace-crypto-$(CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO) := aspeed-hace-crypto.o +-hace-crypto-$(CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO) := aspeed-hace-crypto.o ++hace-crypto-$(CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO) := aspeed-hace-crypto.o aspeed-hace-gcm.o -obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed_crypto.o +obj-$(CONFIG_CRYPTO_DEV_ASPEED_HACE) += aspeed_crypto.o @@ -26592,9 +26331,24 @@ diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile + +obj-$(CONFIG_CRYPTO_DEV_ASPEED_ECDSA) += aspeed-ecdsa.o diff --git a/drivers/crypto/aspeed/aspeed-acry.c b/drivers/crypto/aspeed/aspeed-acry.c ---- a/drivers/crypto/aspeed/aspeed-acry.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-acry.c 2025-12-23 10:16:21.140032401 +0000 -@@ -808,7 +808,7 @@ +--- a/drivers/crypto/aspeed/aspeed-acry.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/aspeed-acry.c 2026-09-09 15:51:44.737237784 +0000 +@@ -789,6 +789,7 @@ + err_engine_rsa_start: + crypto_engine_exit(acry_dev->crypt_engine_rsa); + clk_exit: ++ clk_disable_unprepare(acry_dev->clk); + + return rc; + } +@@ -800,13 +801,14 @@ + aspeed_acry_unregister(acry_dev); + crypto_engine_exit(acry_dev->crypt_engine_rsa); + tasklet_kill(&acry_dev->done_task); ++ clk_disable_unprepare(acry_dev->clk); + } + + MODULE_DEVICE_TABLE(of, aspeed_acry_of_matches); static struct platform_driver aspeed_acry_driver = { .probe = aspeed_acry_probe, @@ -26605,7 +26359,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-acry.c b/drivers/crypto/aspeed/aspeed- .of_match_table = aspeed_acry_of_matches, diff --git a/drivers/crypto/aspeed/aspeed-ecdsa.c b/drivers/crypto/aspeed/aspeed-ecdsa.c --- a/drivers/crypto/aspeed/aspeed-ecdsa.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-ecdsa.c 2025-12-23 10:16:21.140032401 +0000 ++++ b/drivers/crypto/aspeed/aspeed-ecdsa.c 2026-09-09 15:51:44.737237784 +0000 @@ -0,0 +1,779 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -27388,7 +27142,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-ecdsa.c b/drivers/crypto/aspeed/aspeed +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/aspeed/aspeed-ecdsa.h b/drivers/crypto/aspeed/aspeed-ecdsa.h --- a/drivers/crypto/aspeed/aspeed-ecdsa.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-ecdsa.h 2025-12-23 10:16:21.140032401 +0000 ++++ b/drivers/crypto/aspeed/aspeed-ecdsa.h 2026-09-09 15:51:44.737237784 +0000 @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + @@ -27510,21 +27264,43 @@ diff --git a/drivers/crypto/aspeed/aspeed-ecdsa.h b/drivers/crypto/aspeed/aspeed + +#endif diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/aspeed-hace-crypto.c ---- a/drivers/crypto/aspeed/aspeed-hace-crypto.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-hace-crypto.c 2025-12-23 10:16:21.140032401 +0000 -@@ -24,6 +24,11 @@ +--- a/drivers/crypto/aspeed/aspeed-hace-crypto.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/aspeed-hace-crypto.c 2026-09-09 15:51:44.737237784 +0000 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -24,6 +25,25 @@ dev_dbg((h)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) #endif -+#define ASPEED_SEC_PROTECTION 0x0 -+#define SEC_UNLOCK_PASSWORD 0x349fe38a -+#define ASPEED_VAULT_KEY_CTRL 0x80C -+#define SEC_VK_CTRL_VK_SELECTION BIT(0) ++static int aspeed_hace_find_vault_key(struct aspeed_hace_dev *hace_dev, ++ const u8 *key, unsigned int keylen) ++{ ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ int i = 0; ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ for (i = 0; i < crypto_engine->vault_key_num; i++) { ++ if (!crypto_engine->dummy_key[i]) ++ continue; ++ ++ if (memcmp(crypto_engine->dummy_key[i], key, keylen) == 0) ++ return i; ++ } ++ ++ return ASPEED_VAULT_KEY_NOT_FOUND; ++} + static int aspeed_crypto_do_fallback(struct skcipher_request *areq) { struct aspeed_cipher_reqctx *rctx = skcipher_request_ctx(areq); -@@ -143,6 +148,7 @@ +@@ -143,6 +163,7 @@ dma_unmap_sg(dev, req->src, rctx->src_nents, DMA_TO_DEVICE); dma_unmap_sg(dev, req->dst, rctx->dst_nents, DMA_FROM_DEVICE); } @@ -27532,7 +27308,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ return aspeed_sk_complete(hace_dev, 0); } -@@ -206,10 +212,21 @@ +@@ -206,10 +227,21 @@ crypto_engine->resume = aspeed_sk_transfer; /* Trigger engines */ @@ -27554,7 +27330,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ ast_hace_write(hace_dev, req->cryptlen, ASPEED_HACE_DATA_LEN); ast_hace_write(hace_dev, rctx->enc_cmd, ASPEED_HACE_CMD); -@@ -222,21 +239,65 @@ +@@ -222,6 +254,8 @@ struct aspeed_sg_list *src_list, *dst_list; dma_addr_t src_dma_addr, dst_dma_addr; struct aspeed_cipher_reqctx *rctx; @@ -27562,13 +27338,8 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ + struct aspeed_cipher_ctx *ctx; struct skcipher_request *req; struct scatterlist *s; -+ int use_vault_key = 0; int src_sg_len; - int dst_sg_len; - int total, i; - int rc; -+ u32 val; - +@@ -232,6 +266,8 @@ CIPHER_DBG(hace_dev, "\n"); req = crypto_engine->req; @@ -27577,52 +27348,22 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ rctx = skcipher_request_ctx(req); rctx->enc_cmd |= HACE_CMD_DES_SG_CTRL | HACE_CMD_SRC_SG_CTRL | - HACE_CMD_AES_KEY_HW_EXP | HACE_CMD_MBUS_REQ_SYNC_EN; - -+ if (crypto_engine->load_vault_key) { -+ writel(SEC_UNLOCK_PASSWORD, hace_dev->sec_regs + ASPEED_SEC_PROTECTION); -+ CIPHER_DBG(hace_dev, "unlock SB, SEC000=0x%x\n", readl(hace_dev->sec_regs + ASPEED_SEC_PROTECTION)); -+ val = readl(hace_dev->sec_regs + ASPEED_VAULT_KEY_CTRL); -+ if (val & BIT(2)) { -+ if (ctx->dummy_key == 1 && !(val & BIT(0))) { -+ use_vault_key = 1; -+ CIPHER_DBG(hace_dev, "Use Vault key 1\n"); -+ } else if (ctx->dummy_key == 2 && (val & BIT(0))) { -+ use_vault_key = 1; -+ CIPHER_DBG(hace_dev, "Use Vault key 2\n"); -+ } else { -+ use_vault_key = 0; -+ } -+ } else { -+ if (ctx->dummy_key == 1) { -+ use_vault_key = 1; -+ val &= ~SEC_VK_CTRL_VK_SELECTION; -+ writel(val, hace_dev->sec_regs + ASPEED_VAULT_KEY_CTRL); -+ CIPHER_DBG(hace_dev, "Set Vault key 1\n"); -+ } else if (ctx->dummy_key == 2) { -+ use_vault_key = 1; -+ val |= SEC_VK_CTRL_VK_SELECTION; -+ writel(val, hace_dev->sec_regs + ASPEED_VAULT_KEY_CTRL); -+ CIPHER_DBG(hace_dev, "Set Vault key 2\n"); -+ } else { -+ use_vault_key = 0; -+ } -+ } -+ writel(0x0, hace_dev->sec_regs + ASPEED_SEC_PROTECTION); -+ CIPHER_DBG(hace_dev, "lock SB, SEC000=0x%x\n", readl(hace_dev->sec_regs + ASPEED_SEC_PROTECTION)); -+ -+ if (use_vault_key) -+ rctx->enc_cmd |= HACE_CMD_AES_KEY_FROM_OTP; -+ else -+ rctx->enc_cmd &= ~HACE_CMD_AES_KEY_FROM_OTP; -+ } -+ - /* BIDIRECTIONAL */ - if (req->dst == req->src) { +@@ -246,7 +282,6 @@ + dev_warn(hace_dev->dev, "dma_map_sg() src error\n"); + return -EINVAL; + } +- + } else { src_sg_len = dma_map_sg(hace_dev->dev, req->src, -@@ -332,8 +393,19 @@ + rctx->src_nents, DMA_TO_DEVICE); +@@ -331,9 +366,24 @@ + /* Memory barrier to ensure all data setup before engine starts */ mb(); ++ if (crypto_engine->vault_key_num && ++ ctx->key_idx < crypto_engine->vault_key_num) ++ ast_sbc_write(hace_dev, ctx->key_idx, ASPEED_VAULT_KEY_CTRL); ++ /* Trigger engines */ + down(&hace_dev->lock); + ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, @@ -27640,16 +27381,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ ast_hace_write(hace_dev, req->cryptlen, ASPEED_HACE_DATA_LEN); ast_hace_write(hace_dev, rctx->enc_cmd, ASPEED_HACE_CMD); -@@ -346,7 +418,7 @@ - - } else { - dma_unmap_sg(hace_dev->dev, req->dst, rctx->dst_nents, -- DMA_TO_DEVICE); -+ DMA_FROM_DEVICE); - dma_unmap_sg(hace_dev->dev, req->src, rctx->src_nents, - DMA_TO_DEVICE); - } -@@ -380,9 +452,6 @@ +@@ -380,9 +430,6 @@ rctx->dst_nents = sg_nents(req->dst); rctx->src_nents = sg_nents(req->src); @@ -27659,7 +27391,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ if (rctx->enc_cmd & HACE_CMD_IV_REQUIRE) { if (rctx->enc_cmd & HACE_CMD_DES_SELECT) memcpy(crypto_engine->cipher_ctx + DES_BLOCK_SIZE, -@@ -392,7 +461,8 @@ +@@ -392,7 +439,8 @@ AES_BLOCK_SIZE); } @@ -27669,67 +27401,110 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ memcpy(crypto_engine->cipher_ctx + 16, ctx->key, ctx->key_len); return aspeed_sk_start_sg(hace_dev); -@@ -580,6 +650,8 @@ +@@ -435,6 +483,9 @@ + + CIPHER_DBG(hace_dev, "keylen: %d bits\n", keylen); + ++ /* DES does not support vault key */ ++ ctx->key_idx = ASPEED_VAULT_KEY_NOT_FOUND; ++ + if (keylen != DES_KEY_SIZE && keylen != DES3_EDE_KEY_SIZE) { + dev_warn(hace_dev->dev, "invalid keylen: %d bits\n", keylen); + return -EINVAL; +@@ -539,6 +590,7 @@ + struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); + struct aspeed_cipher_ctx *ctx = crypto_skcipher_ctx(cipher); + struct aspeed_hace_dev *hace_dev = ctx->hace_dev; ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; + u32 crypto_alg = cmd & HACE_CMD_OP_MODE_MASK; + + if (crypto_alg == HACE_CMD_CBC || crypto_alg == HACE_CMD_ECB) { +@@ -552,6 +604,9 @@ + cmd |= HACE_CMD_AES_SELECT | HACE_CMD_RI_WO_DATA_ENABLE | + HACE_CMD_CONTEXT_LOAD_ENABLE | HACE_CMD_CONTEXT_SAVE_ENABLE; + ++ if (ctx->key_idx < crypto_engine->vault_key_num) ++ cmd |= HACE_CMD_AES_KEY_FROM_OTP; ++ + switch (ctx->key_len) { + case AES_KEYSIZE_128: + cmd |= HACE_CMD_AES128; +@@ -580,6 +635,8 @@ CIPHER_DBG(hace_dev, "keylen: %d bits\n", (keylen * 8)); -+ ctx->dummy_key = find_dummy_key(key, keylen); ++ ctx->key_idx = aspeed_hace_find_vault_key(hace_dev, key, keylen); + if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_256) return -EINVAL; -@@ -919,19 +991,49 @@ - for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs); i++) - crypto_engine_unregister_skcipher(&aspeed_crypto_algs[i].alg.skcipher); +@@ -635,9 +692,8 @@ + { + struct aspeed_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); +- const char *name = crypto_tfm_alg_name(&tfm->base); + struct aspeed_hace_alg *crypto_alg; +- ++ const char *name = crypto_tfm_alg_name(&tfm->base); -- if (hace_dev->version != AST2600_VERSION) -+ if (hace_dev->version == AST2500_VERSION) - return; + crypto_alg = container_of(alg, struct aspeed_hace_alg, alg.skcipher.base); + ctx->hace_dev = crypto_alg->hace_dev; +@@ -912,6 +968,45 @@ - for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) - crypto_engine_unregister_skcipher(&aspeed_crypto_algs_g6[i].alg.skcipher); - } + }; -+#ifdef CONFIG_AST2600_OTP -+static void find_vault_key(struct aspeed_hace_dev *hace_dev) ++void aspeed_register_hace_vault_key(struct aspeed_hace_dev *hace_dev) +{ ++ struct device *dev = hace_dev->dev; + struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; -+ u32 otp_data[16]; -+ int i; ++ static const char * const key[] = { ASPEED_VAULT_KEY_DTS }; ++ int i = 0; ++ int err = 0; ++ int key_num = hace_dev->version == AST2700_VERSION ? ++ ASPEED_G7_VAULT_KEY_MAX_NUM : ++ ASPEED_G6_VAULT_KEY_MAX_NUM; + -+ crypto_engine->load_vault_key = 0; ++ crypto_engine->vault_key_num = 0; + -+ otp_read_data_buf(0, otp_data, 16); -+ for (i = 0; i < 16; i++) { -+ CIPHER_DBG(hace_dev, "OTPDATA%d=%x\n", i, otp_data[i]); -+ if (((otp_data[i] >> 14) & 0xf) == 1) { -+ CIPHER_DBG(hace_dev, "Found vault key in OTP\n"); -+ crypto_engine->load_vault_key = 1; -+ return; ++ if (hace_dev->version == AST2500_VERSION) ++ return; ++ ++ /* Check all vault key from dts and store in dummy_key array */ ++ for (i = 0; i < key_num; i++) { ++ crypto_engine->dummy_key[i] = ++ devm_kzalloc(dev, DUMMY_KEY_SIZE, GFP_KERNEL); ++ if (!crypto_engine->dummy_key[i]) { ++ dev_err(dev, "Failed to allocate memory for %s\n", key[i]); ++ continue; + } -+ if (otp_data[i] & BIT(13)) -+ break; ++ ++ err = of_property_read_u32_array(dev->of_node, key[i], ++ crypto_engine->dummy_key[i], ++ DUMMY_KEY_SIZE / sizeof(u32)); ++ if (err) { ++ dev_err(dev, "Cannot find %s, skip key register\n", key[i]); ++ devm_kfree(dev, crypto_engine->dummy_key[i]); ++ crypto_engine->dummy_key[i] = NULL; ++ continue; ++ } ++ ++ crypto_engine->vault_key_num = key_num; + } -+ CIPHER_DBG(hace_dev, "Not found vault key in OTP\n"); +} -+#endif + - void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev) + void aspeed_unregister_hace_crypto_algs(struct aspeed_hace_dev *hace_dev) { - int rc, i; + int i; +@@ -919,7 +1014,7 @@ + for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs); i++) + crypto_engine_unregister_skcipher(&aspeed_crypto_algs[i].alg.skcipher); - CIPHER_DBG(hace_dev, "\n"); +- if (hace_dev->version != AST2600_VERSION) ++ if (hace_dev->version == AST2500_VERSION) + return; -+#ifdef CONFIG_AST2600_OTP -+ find_vault_key(hace_dev); -+#else -+ hace_dev->crypto_engine.load_vault_key = 0; -+#endif -+ - for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs); i++) { - aspeed_crypto_algs[i].hace_dev = hace_dev; - rc = crypto_engine_register_skcipher(&aspeed_crypto_algs[i].alg.skcipher); -@@ -941,7 +1043,7 @@ + for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) +@@ -941,7 +1036,7 @@ } } @@ -27738,7 +27513,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ return; for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) { -@@ -953,3 +1055,88 @@ +@@ -953,3 +1048,94 @@ } } } @@ -27812,6 +27587,12 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ + } + } + ++ /* Re-use destination buffer for aes-gcm tag output */ ++ crypto_engine->tag_addr = crypto_engine->dst_sg_addr + ++ ASPEED_CRYPTO_DST_DMA_BUF_LEN - AES_BLOCK_SIZE; ++ crypto_engine->tag_dma_addr = crypto_engine->dst_sg_dma_addr + ++ ASPEED_CRYPTO_DST_DMA_BUF_LEN - AES_BLOCK_SIZE; ++ + return 0; + +err_engine_crypto_start: @@ -27827,9 +27608,505 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/ + crypto_engine_exit(hace_dev->crypt_engine_crypto); + tasklet_kill(&crypto_engine->done_task); +} +diff --git a/drivers/crypto/aspeed/aspeed-hace-gcm.c b/drivers/crypto/aspeed/aspeed-hace-gcm.c +--- a/drivers/crypto/aspeed/aspeed-hace-gcm.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/crypto/aspeed/aspeed-hace-gcm.c 2026-09-09 15:51:44.737237784 +0000 +@@ -0,0 +1,492 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2026 Aspeed Technology Inc. ++ */ ++ ++#include "aspeed-hace.h" ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO_DEBUG ++#define CIPHER_DBG(h, fmt, ...) \ ++ dev_info((h)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) ++#else ++#define CIPHER_DBG(h, fmt, ...) \ ++ dev_dbg((h)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) ++#endif ++ ++static bool aspeed_crypto_aead_need_fallback(struct aead_request *areq) ++{ ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(areq); ++ ++ if (areq->assoclen != 0) ++ return true; ++ ++ if (rctx->enc_cmd & HACE_CMD_ENCRYPT && areq->cryptlen == 0) ++ return true; ++ ++ if (!(rctx->enc_cmd & HACE_CMD_ENCRYPT) && ++ areq->cryptlen == AES_GCM_TAG_SIZE) ++ return true; ++ ++ return false; ++} ++ ++static int aspeed_crypto_aead_do_fallback(struct aead_request *areq) ++{ ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(areq); ++ struct crypto_aead *tfm = crypto_aead_reqtfm(areq); ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(tfm); ++ int err; ++ ++ aead_request_set_tfm(&rctx->fallback_aead_req, ctx->fallback_aead_tfm); ++ ++ aead_request_set_callback(&rctx->fallback_aead_req, areq->base.flags, ++ NULL, NULL); ++ aead_request_set_crypt(&rctx->fallback_aead_req, areq->src, areq->dst, ++ areq->cryptlen, areq->iv); ++ aead_request_set_ad(&rctx->fallback_aead_req, areq->assoclen); ++ ++ if (rctx->enc_cmd & HACE_CMD_ENCRYPT) ++ err = crypto_aead_encrypt(&rctx->fallback_aead_req); ++ else ++ err = crypto_aead_decrypt(&rctx->fallback_aead_req); ++ ++ return err; ++} ++ ++static int ++aspeed_hace_crypto_aead_handle_queue(struct aspeed_hace_dev *hace_dev, ++ struct aead_request *req) ++{ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ if (aspeed_crypto_aead_need_fallback(req)) ++ return aspeed_crypto_aead_do_fallback(req); ++ ++ return crypto_transfer_aead_request_to_engine(hace_dev->crypt_engine_crypto, req); ++} ++ ++static void aspeed_hace_aead_sg_unmap(struct aspeed_hace_dev *hace_dev, ++ struct aead_request *req) ++{ ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ ++ if (rctx->dst_sg_len) { ++ dma_unmap_sg(hace_dev->dev, req->dst, rctx->dst_nents, ++ DMA_FROM_DEVICE); ++ } ++ ++ if (rctx->src_sg_len) { ++ dma_unmap_sg(hace_dev->dev, req->src, rctx->src_nents, ++ DMA_TO_DEVICE); ++ } ++} ++ ++static int aspeed_hace_aead_sg_map(struct aspeed_hace_dev *hace_dev, ++ struct aead_request *req) ++{ ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ rctx->src_sg_len = dma_map_sg(hace_dev->dev, req->src, rctx->src_nents, ++ DMA_TO_DEVICE); ++ if (!rctx->src_sg_len) { ++ dev_warn(hace_dev->dev, "dma_map_sg() src error\n"); ++ return -EINVAL; ++ } ++ ++ rctx->dst_sg_len = dma_map_sg(hace_dev->dev, req->dst, rctx->dst_nents, ++ DMA_FROM_DEVICE); ++ if (!rctx->dst_sg_len) { ++ dev_warn(hace_dev->dev, "dma_map_sg() dst error\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int aspeed_hace_aead_build_sg(struct aspeed_sg_list *sg_list, ++ struct scatterlist *src_sg, int src_sg_len, ++ int total) ++{ ++ struct scatterlist *s; ++ int i; ++ ++ for_each_sg(src_sg, s, src_sg_len, i) { ++ u32 phy_addr = sg_dma_address(s); ++ u32 len = sg_dma_len(s); ++ ++ len = total > len ? len : total | BIT(31); ++ total = total > len ? total - len : 0; ++ ++ sg_list[i].phy_addr = cpu_to_le32(phy_addr); ++ sg_list[i].len = cpu_to_le32(len); ++ } ++ ++ sg_list[src_sg_len].phy_addr = 0; ++ sg_list[src_sg_len].len = 0; ++ ++ if (total != 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int aspeed_aead_complete(struct aspeed_hace_dev *hace_dev, int err) ++{ ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ struct aead_request *req = crypto_engine->aead_req; ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ ++ if (rctx->enc_cmd & HACE_CMD_ENCRYPT) ++ scatterwalk_map_and_copy(crypto_engine->tag_addr, req->dst, ++ req->cryptlen, AES_GCM_TAG_SIZE, 1); ++ ++ if (!(rctx->enc_cmd & HACE_CMD_ENCRYPT)) ++ req->cryptlen += AES_GCM_TAG_SIZE; ++ ++ crypto_engine->flags &= ~CRYPTO_FLAGS_BUSY; ++ ++ crypto_finalize_aead_request(hace_dev->crypt_engine_crypto, req, err); ++ ++ return err; ++} ++ ++static int aspeed_aead_transfer_sg(struct aspeed_hace_dev *hace_dev) ++{ ++ struct aead_request *req = hace_dev->crypto_engine.aead_req; ++ ++ aspeed_hace_aead_sg_unmap(hace_dev, req); ++ up(&hace_dev->lock); ++ ++ return aspeed_aead_complete(hace_dev, 0); ++} ++ ++static void aspeed_hace_trigger(struct aspeed_hace_dev *hace_dev) ++{ ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ struct aead_request *req = crypto_engine->aead_req; ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ down(&hace_dev->lock); ++ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, ++ ASPEED_HACE_CONTEXT); ++ ast_hace_write(hace_dev, crypto_engine->tag_dma_addr, ++ ASPEED_HACE_GCM_TAG_BASE_ADDR); ++ ast_hace_write(hace_dev, crypto_engine->cipher_dma_addr, ++ ASPEED_HACE_SRC); ++ ast_hace_write(hace_dev, crypto_engine->dst_sg_dma_addr, ++ ASPEED_HACE_DEST); ++ ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ ast_hace_write(hace_dev, crypto_engine->tag_dma_addr >> 32, ++ ASPEED_HACE_TAG_H); ++ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma >> 32, ++ ASPEED_HACE_CONTEXT_H); ++ ast_hace_write(hace_dev, crypto_engine->cipher_dma_addr >> 32, ++ ASPEED_HACE_SRC_H); ++ ast_hace_write(hace_dev, crypto_engine->dst_sg_dma_addr >> 32, ++ ASPEED_HACE_DEST_H); ++#endif ++ ++ ast_hace_write(hace_dev, req->cryptlen, ASPEED_HACE_DATA_LEN); ++ ast_hace_write(hace_dev, req->assoclen, ASPEED_HACE_GCM_ADD_LEN); ++ ast_hace_write(hace_dev, rctx->enc_cmd, ASPEED_HACE_CMD); ++} ++ ++static int aspeed_aead_start_sg(struct aspeed_hace_dev *hace_dev) ++{ ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ struct aead_request *req = crypto_engine->aead_req; ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ struct aspeed_sg_list *src_list, *dst_list; ++ int ret = 0; ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ /* Scatter list mapping */ ++ ret = aspeed_hace_aead_sg_map(hace_dev, req); ++ if (ret) ++ goto fail; ++ ++ /* Build scatter-gather source list */ ++ src_list = (struct aspeed_sg_list *)crypto_engine->cipher_addr; ++ ret = aspeed_hace_aead_build_sg(src_list, req->src, rctx->src_sg_len, ++ req->cryptlen); ++ if (ret) ++ goto fail; ++ ++ /* Build scatter-gather destination list */ ++ dst_list = (struct aspeed_sg_list *)crypto_engine->dst_sg_addr; ++ ret = aspeed_hace_aead_build_sg(dst_list, req->dst, rctx->dst_sg_len, ++ req->cryptlen); ++ if (ret) ++ goto fail; ++ ++ crypto_engine->resume = aspeed_aead_transfer_sg; ++ ++ /* Memory barrier to ensure all data setup before engine starts */ ++ mb(); ++ aspeed_hace_trigger(hace_dev); ++ ++ return -EINPROGRESS; ++fail: ++ aspeed_hace_aead_sg_unmap(hace_dev, req); ++ return ret; ++} ++ ++static int aspeed_hace_aead_subkey(u8 *subkey, u8 *key, u32 keylen) ++{ ++ struct crypto_cipher *tfm = NULL; ++ int ret; ++ u8 src[AES_BLOCK_SIZE] = { 0 }; ++ ++ tfm = crypto_alloc_cipher("aes", 0, 0); ++ if (IS_ERR(tfm)) ++ return PTR_ERR(tfm); ++ ++ ret = crypto_cipher_setkey(tfm, key, keylen); ++ if (ret) ++ goto out; ++ ++ /* Encrypt one 16-byte block */ ++ crypto_cipher_encrypt_one(tfm, subkey, src); ++ ++out: ++ crypto_free_cipher(tfm); ++ return ret; ++} ++ ++static int aspeed_hace_aead_trigger(struct aspeed_hace_dev *hace_dev) ++{ ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ struct aead_request *req = crypto_engine->aead_req; ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ u8 iv_count[] = { 0x00, 0x00, 0x00, 0x01 }; ++ u8 subkey_offset = 0; ++ u8 subkey[AES_BLOCK_SIZE] = { 0 }; ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ if (!(rctx->enc_cmd & HACE_CMD_ENCRYPT)) ++ req->cryptlen = req->cryptlen - AES_GCM_TAG_SIZE; ++ ++ aspeed_hace_aead_subkey(subkey, ctx->key, ctx->key_len); ++ if (ctx->key_len == AES_KEYSIZE_128) ++ subkey_offset = ASPEED_HACE_CTX_128_SUBKEY_OFFSET; ++ else ++ subkey_offset = ASPEED_HACE_CTX_256_SUBKEY_OFFSET; ++ ++ rctx->dst_nents = sg_nents(req->dst); ++ rctx->src_nents = sg_nents(req->src); ++ ++ memcpy(crypto_engine->cipher_ctx, req->iv, GCM_AES_IV_SIZE); ++ memcpy(crypto_engine->cipher_ctx + GCM_AES_IV_SIZE, iv_count, ++ sizeof(iv_count)); ++ memcpy(crypto_engine->cipher_ctx + ASPEED_HACE_CTX_KEY_OFFSET, ctx->key, ++ ctx->key_len); ++ memcpy(crypto_engine->cipher_ctx + subkey_offset, subkey, ++ AES_BLOCK_SIZE); ++ ++ return aspeed_aead_start_sg(hace_dev); ++} ++ ++static int aspeed_aes_aead_setkey(struct crypto_aead *aead, const u8 *key, ++ unsigned int keylen) ++{ ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ struct aspeed_hace_dev *hace_dev = ctx->hace_dev; ++ ++ CIPHER_DBG(hace_dev, "keylen: %d bits\n", (keylen * 8)); ++ ++ ctx->key_idx = ASPEED_VAULT_KEY_NOT_FOUND; ++ ++ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && ++ keylen != AES_KEYSIZE_256) ++ return -EINVAL; ++ ++ memcpy(ctx->key, key, keylen); ++ ctx->key_len = keylen; ++ ++ crypto_aead_clear_flags(ctx->fallback_aead_tfm, CRYPTO_TFM_REQ_MASK); ++ crypto_aead_set_flags(ctx->fallback_aead_tfm, ++ aead->base.crt_flags & CRYPTO_TFM_REQ_MASK); ++ ++ return crypto_aead_setkey(ctx->fallback_aead_tfm, key, keylen); ++} ++ ++static int aspeed_aes_aead_setauthsize(struct crypto_aead *aead, ++ unsigned int authsize) ++{ ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ struct aspeed_hace_dev *hace_dev = ctx->hace_dev; ++ ++ CIPHER_DBG(hace_dev, "authsize: %d bits\n", (authsize * 8)); ++ ++ return crypto_aead_setauthsize(ctx->fallback_aead_tfm, authsize); ++} ++ ++static int aspeed_aes_gcm_crypt(struct aead_request *req, u32 cmd) ++{ ++ struct aspeed_cipher_reqctx *rctx = aead_request_ctx(req); ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ struct aspeed_hace_dev *hace_dev = ctx->hace_dev; ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ cmd = cmd | HACE_CMD_GCM | HACE_CMD_AES_SELECT | ++ HACE_CMD_RI_WO_DATA_ENABLE | HACE_CMD_CONTEXT_LOAD_ENABLE | ++ HACE_CMD_CONTEXT_SAVE_ENABLE | HACE_CMD_ISR_EN | ++ HACE_CMD_DES_SG_CTRL | HACE_CMD_SRC_SG_CTRL | ++ HACE_CMD_AES_KEY_HW_EXP | HACE_CMD_MBUS_REQ_SYNC_EN | ++ HACE_CMD_CTR_IV_AES_96 | HACE_CMD_GCM_TAG_ADDR_SEL; ++ ++ switch (ctx->key_len) { ++ case AES_KEYSIZE_128: ++ cmd |= HACE_CMD_AES128; ++ break; ++ case AES_KEYSIZE_192: ++ cmd |= HACE_CMD_AES192; ++ break; ++ case AES_KEYSIZE_256: ++ cmd |= HACE_CMD_AES256; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ rctx->enc_cmd = cmd; ++ ++ return aspeed_hace_crypto_aead_handle_queue(ctx->hace_dev, req); ++} ++ ++static int aspeed_aes_gcm_encrypt(struct aead_request *req) ++{ ++ return aspeed_aes_gcm_crypt(req, HACE_CMD_ENCRYPT); ++} ++ ++static int aspeed_aes_gcm_decrypt(struct aead_request *req) ++{ ++ return aspeed_aes_gcm_crypt(req, HACE_CMD_DECRYPT); ++} ++ ++static int aspeed_aead_do_request(struct crypto_engine *engine, void *areq) ++{ ++ struct aead_request *req = aead_request_cast(areq); ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ struct aspeed_hace_dev *hace_dev = ctx->hace_dev; ++ struct aspeed_engine_crypto *crypto_engine; ++ int rc; ++ ++ crypto_engine = &hace_dev->crypto_engine; ++ crypto_engine->aead_req = (struct aead_request *)req; ++ crypto_engine->flags |= CRYPTO_FLAGS_BUSY; ++ ++ rc = aspeed_hace_aead_trigger(hace_dev); ++ if (rc != -EINPROGRESS) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int aspeed_crypto_aead_init(struct crypto_aead *aead) ++{ ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ struct aead_alg *alg = crypto_aead_alg(aead); ++ struct aspeed_hace_alg *crypto_alg = NULL; ++ const char *name = crypto_tfm_alg_name(&aead->base); ++ ++ crypto_alg = container_of(alg, struct aspeed_hace_alg, alg.aead.base); ++ ctx->hace_dev = crypto_alg->hace_dev; ++ ++ CIPHER_DBG(ctx->hace_dev, "\n"); ++ ++ ctx->fallback_aead_tfm = ++ crypto_alloc_aead(name, 0, CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->fallback_aead_tfm)) { ++ dev_err(ctx->hace_dev->dev, "Failed to allocate %s %ld\n", name, ++ PTR_ERR(ctx->fallback_aead_tfm)); ++ return PTR_ERR(ctx->fallback_aead_tfm); ++ } ++ ++ crypto_aead_set_reqsize(aead, sizeof(struct aead_request) + ++ crypto_aead_reqsize(ctx->fallback_aead_tfm)); ++ ++ return 0; ++} ++ ++static void aspeed_crypto_aead_exit(struct crypto_aead *aead) ++{ ++ struct aspeed_cipher_ctx *ctx = crypto_aead_ctx(aead); ++ struct aspeed_hace_dev *hace_dev = ctx->hace_dev; ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ if (ctx->fallback_aead_tfm) { ++ crypto_free_aead(ctx->fallback_aead_tfm); ++ ctx->fallback_aead_tfm = NULL; ++ } ++ ++ memzero_explicit(ctx, sizeof(struct aspeed_cipher_ctx)); ++} ++ ++static struct aspeed_hace_alg aspeed_aead_algs[] = { ++ { ++ .alg.aead.base = { ++ .ivsize = GCM_AES_IV_SIZE, ++ .maxauthsize = AES_BLOCK_SIZE, ++ .setkey = aspeed_aes_aead_setkey, ++ .setauthsize = aspeed_aes_aead_setauthsize, ++ .encrypt = aspeed_aes_gcm_encrypt, ++ .decrypt = aspeed_aes_gcm_decrypt, ++ .init = aspeed_crypto_aead_init, ++ .exit = aspeed_crypto_aead_exit, ++ .base = { ++ .cra_name = "gcm(aes)", ++ .cra_driver_name = "aspeed-gcm-aes", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AEAD | ++ CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_NEED_FALLBACK, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), ++ .cra_alignmask = 0x0f, ++ .cra_module = THIS_MODULE, ++ } ++ }, ++ .alg.aead.op = { ++ .do_one_request = aspeed_aead_do_request, ++ }, ++ }, ++}; ++ ++void aspeed_register_hace_aead_algs(struct aspeed_hace_dev *hace_dev) ++{ ++ int rc, i; ++ ++ CIPHER_DBG(hace_dev, "\n"); ++ ++ if (hace_dev->version == AST2500_VERSION || ++ hace_dev->version == AST2600_VERSION) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(aspeed_aead_algs); i++) { ++ aspeed_aead_algs[i].hace_dev = hace_dev; ++ rc = crypto_engine_register_aead(&aspeed_aead_algs[i].alg.aead); ++ if (rc) { ++ CIPHER_DBG(hace_dev, "Failed to register %s\n", ++ aspeed_aead_algs[i].alg.aead.base.base.cra_name); ++ } ++ } ++} diff --git a/drivers/crypto/aspeed/aspeed-hace-hash.c b/drivers/crypto/aspeed/aspeed-hace-hash.c ---- a/drivers/crypto/aspeed/aspeed-hace-hash.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-hace-hash.c 2025-12-23 10:16:21.140032401 +0000 +--- a/drivers/crypto/aspeed/aspeed-hace-hash.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/aspeed-hace-hash.c 2026-09-09 15:51:44.737237784 +0000 @@ -138,21 +138,13 @@ return -EINVAL; } @@ -28303,9 +28580,9 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace-hash.c b/drivers/crypto/aspeed/as + tasklet_kill(&hash_engine->done_task); +} diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed-hace.c ---- a/drivers/crypto/aspeed/aspeed-hace.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-hace.c 2025-12-23 10:16:21.140032401 +0000 -@@ -6,15 +6,18 @@ +--- a/drivers/crypto/aspeed/aspeed-hace.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/aspeed-hace.c 2026-09-09 15:51:44.737237784 +0000 +@@ -6,15 +6,17 @@ #include "aspeed-hace.h" #include #include @@ -28316,7 +28593,6 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- #include #include #include -+#include +#include +#include #include @@ -28325,25 +28601,10 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- #ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG #define HACE_DBG(d, fmt, ...) \ -@@ -24,6 +27,45 @@ +@@ -24,6 +26,30 @@ dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) #endif -+static unsigned char *dummy_key1; -+static unsigned char *dummy_key2; -+ -+int find_dummy_key(const char *key, int keylen) -+{ -+ int ret = 0; -+ -+ if (dummy_key1 && memcmp(key, dummy_key1, keylen) == 0) -+ ret = 1; -+ else if (dummy_key2 && memcmp(key, dummy_key2, keylen) == 0) -+ ret = 2; -+ -+ return ret; -+} -+ +int aspeed_hace_reset(struct aspeed_hace_dev *hace_dev) +{ + int rc; @@ -28371,7 +28632,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- /* HACE interrupt service routine */ static irqreturn_t aspeed_hace_irq(int irq, void *dev) { -@@ -51,23 +93,9 @@ +@@ -51,23 +77,9 @@ dev_warn(hace_dev->dev, "CRYPTO no active requests.\n"); } @@ -28397,7 +28658,16 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- } static void aspeed_hace_register(struct aspeed_hace_dev *hace_dev) -@@ -93,30 +121,35 @@ +@@ -77,6 +89,8 @@ + #endif + #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO + aspeed_register_hace_crypto_algs(hace_dev); ++ aspeed_register_hace_aead_algs(hace_dev); ++ aspeed_register_hace_vault_key(hace_dev); + #endif + } + +@@ -93,30 +107,31 @@ static const struct of_device_id aspeed_hace_of_matches[] = { { .compatible = "aspeed,ast2500-hace", .data = (void *)5, }, { .compatible = "aspeed,ast2600-hace", .data = (void *)6, }, @@ -28413,10 +28683,6 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- struct aspeed_hace_dev *hace_dev; + struct device *dev = &pdev->dev; int rc; -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO -+ struct device_node *sec_node; -+ int err; -+#endif + /* Allocate and register hace driver in linux kernel */ hace_dev = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_hace_dev), @@ -28439,7 +28705,18 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- platform_set_drvdata(pdev, hace_dev); -@@ -149,115 +182,93 @@ +@@ -124,6 +139,10 @@ + if (IS_ERR(hace_dev->regs)) + return PTR_ERR(hace_dev->regs); + ++ hace_dev->sbc = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); ++ if (IS_ERR(hace_dev->sbc)) ++ return PTR_ERR(hace_dev->sbc); ++ + /* Get irq number and register it */ + hace_dev->irq = platform_get_irq(pdev, 0); + if (hace_dev->irq < 0) +@@ -149,115 +168,68 @@ return rc; } @@ -28520,19 +28797,26 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- - dev_err(&pdev->dev, "Failed to allocate dst_sg dma\n"); - rc = -ENOMEM; - goto err_engine_crypto_start; +- } + /* Get rst and de-assert reset */ + hace_dev->rst = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(hace_dev->rst)) { + dev_err(&pdev->dev, "Failed to get hace reset\n"); + return PTR_ERR(hace_dev->rst); -+ } -+ + } + + rc = reset_control_deassert(hace_dev->rst); + if (rc) { + dev_err(&pdev->dev, "Deassert hace reset failed\n"); + return rc; + } + ++ rc = aspeed_hace_reset(hace_dev); ++ if (rc) { ++ dev_err(&pdev->dev, "Hace reset failed\n"); ++ return rc; ++ } ++ + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) { + dev_warn(&pdev->dev, "No suitable DMA available\n"); @@ -28555,37 +28839,6 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- + dev_err(&pdev->dev, "Crypto init failed\n"); + return rc; + } -+ -+ if (of_find_property(dev->of_node, "dummy-key1", NULL)) { -+ dummy_key1 = kzalloc(DUMMY_KEY_SIZE, GFP_KERNEL); -+ if (dummy_key1) { -+ err = of_property_read_u8_array(dev->of_node, "dummy-key1", dummy_key1, DUMMY_KEY_SIZE); -+ if (err) -+ dev_err(dev, "error of reading dummy_key 1\n"); -+ } else { -+ dev_err(dev, "error dummy_key1 allocation\n"); - } - } - -+ if (of_find_property(dev->of_node, "dummy-key2", NULL)) { -+ dummy_key2 = kzalloc(DUMMY_KEY_SIZE, GFP_KERNEL); -+ if (dummy_key2) { -+ err = of_property_read_u8_array(dev->of_node, "dummy-key2", dummy_key2, DUMMY_KEY_SIZE); -+ if (err) -+ dev_err(dev, "error of reading dummy_key 2\n"); -+ } else { -+ dev_err(dev, "error dummy_key2 allocation\n"); -+ } -+ } -+ -+ sec_node = of_find_compatible_node(NULL, NULL, "aspeed,ast2600-sbc"); -+ if (!sec_node) { -+ dev_err(dev, "cannot find sbc node\n"); -+ } else { -+ hace_dev->sec_regs = of_iomap(sec_node, 0); -+ if (!hace_dev->sec_regs) -+ dev_err(dev, "failed to map SBC registers\n"); -+ } +#endif aspeed_hace_register(hace_dev); @@ -28625,7 +28878,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- clk_disable_unprepare(hace_dev->clk); } -@@ -266,7 +277,7 @@ +@@ -266,7 +238,7 @@ static struct platform_driver aspeed_hace_driver = { .probe = aspeed_hace_probe, @@ -28635,8 +28888,8 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed- .name = KBUILD_MODNAME, .of_match_table = aspeed_hace_of_matches, diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed-hace.h ---- a/drivers/crypto/aspeed/aspeed-hace.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-hace.h 2025-12-23 10:16:21.140032401 +0000 +--- a/drivers/crypto/aspeed/aspeed-hace.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/crypto/aspeed/aspeed-hace.h 2026-09-09 15:51:44.737237784 +0000 @@ -10,6 +10,8 @@ #include #include @@ -28655,7 +28908,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- /* G6 */ #define ASPEED_HACE_GCM_ADD_LEN 0x14 /* Crypto AES-GCM Additional Data Length Register */ #define ASPEED_HACE_GCM_TAG_BASE_ADDR 0x18 /* Crypto AES-GCM Tag Write Buff Base Address Reg */ -@@ -36,6 +38,15 @@ +@@ -36,6 +38,22 @@ #define ASPEED_HACE_HASH_DATA_LEN 0x2C /* Hash Data Length Register */ #define ASPEED_HACE_HASH_CMD 0x30 /* Hash Engine Command Register */ @@ -28667,11 +28920,18 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- +#define ASPEED_HACE_HASH_SRC_H 0x90 /* Hash Data Source Base High Address Register */ +#define ASPEED_HACE_HASH_DIGEST_BUFF_H 0x94 /* Hash Digest Write Buffer Base High Address Register */ +#define ASPEED_HACE_HASH_KEY_BUFF_H 0x98 /* Hash HMAC Key Buffer Base High Address Register */ ++ ++/***************************** ++ * * ++ * SBC register definitions * ++ * * ++ * ***************************/ ++#define ASPEED_VAULT_KEY_CTRL 0x00C + /* crypto cmd */ #define HACE_CMD_SINGLE_DES 0 #define HACE_CMD_TRIPLE_DES BIT(17) -@@ -109,8 +120,9 @@ +@@ -109,8 +127,9 @@ #define CRYPTO_FLAGS_BUSY BIT(1) @@ -28683,16 +28943,29 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- #define SHA_FLAGS_SHA1 BIT(0) #define SHA_FLAGS_SHA224 BIT(1) -@@ -132,6 +144,8 @@ - #define HACE_CMD_IV_REQUIRE (HACE_CMD_CBC | HACE_CMD_CFB | \ - HACE_CMD_OFB | HACE_CMD_CTR) - +@@ -129,8 +148,19 @@ + #define ASPEED_HASH_SRC_DMA_BUF_LEN 0xa000 + #define ASPEED_HASH_QUEUE_LENGTH 50 + +-#define HACE_CMD_IV_REQUIRE (HACE_CMD_CBC | HACE_CMD_CFB | \ +- HACE_CMD_OFB | HACE_CMD_CTR) ++#define HACE_CMD_IV_REQUIRE \ ++ (HACE_CMD_CBC | HACE_CMD_CFB | HACE_CMD_OFB | HACE_CMD_CTR) ++#define ASPEED_HACE_CTX_KEY_OFFSET (0x10) ++#define ASPEED_HACE_CTX_128_SUBKEY_OFFSET (0x20) ++#define ASPEED_HACE_CTX_256_SUBKEY_OFFSET (0x30) ++#define AES_GCM_TAG_SIZE (16) ++ ++#define ASPEED_VAULT_KEY_NOT_FOUND (0xffffffff) ++#define ASPEED_G6_VAULT_KEY_MAX_NUM 2 ++#define ASPEED_G7_VAULT_KEY_MAX_NUM 4 +#define DUMMY_KEY_SIZE 32 -+ ++#define ASPEED_VAULT_KEY_DTS \ ++ "dummy-key0", "dummy-key1", "dummy-key2", "dummy-key3" + struct aspeed_hace_dev; struct scatterlist; - -@@ -147,10 +161,21 @@ +@@ -147,10 +177,21 @@ unsigned long flags; struct ahash_request *req; @@ -28714,7 +28987,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- dma_addr_t src_dma; dma_addr_t digest_dma; -@@ -192,12 +217,10 @@ +@@ -192,12 +233,10 @@ /* remain data buffer */ u8 buffer[SHA512_BLOCK_SIZE * 2]; @@ -28728,26 +29001,60 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- u64 digcnt[2]; }; -@@ -220,12 +243,14 @@ +@@ -205,6 +244,7 @@ + struct tasklet_struct done_task; + unsigned long flags; + struct skcipher_request *req; ++ struct aead_request *aead_req; + + /* context buffer */ + void *cipher_ctx; +@@ -218,36 +258,54 @@ + void *dst_sg_addr; + dma_addr_t dst_sg_dma_addr; ++ /* tag buffer, only used in scatter-gather lists */ ++ void *tag_addr; ++ dma_addr_t tag_dma_addr; ++ ++ /* Vault key */ ++ u32 *dummy_key[4]; ++ int vault_key_num; ++ /* callback func */ - aspeed_hace_fn_t resume; -+ int load_vault_key; +- aspeed_hace_fn_t resume; ++ aspeed_hace_fn_t resume; }; struct aspeed_cipher_ctx { struct aspeed_hace_dev *hace_dev; int key_len; u8 key[AES_MAX_KEYLENGTH]; -+ int dummy_key; ++ u32 key_idx; /* callback func */ aspeed_hace_fn_t start; -@@ -243,11 +268,16 @@ + +- struct crypto_skcipher *fallback_tfm; ++ struct crypto_aead *fallback_aead_tfm; ++ struct crypto_skcipher *fallback_tfm; + }; + + struct aspeed_cipher_reqctx { + int enc_cmd; + int src_nents; ++ int src_sg_len; + int dst_nents; ++ int dst_sg_len; + +- struct skcipher_request fallback_req; /* keep at the end */ ++ struct aead_request fallback_aead_req; ++ struct skcipher_request fallback_req; /* keep at the end */ + }; struct aspeed_hace_dev { void __iomem *regs; -+ void __iomem *sec_regs; ++ void __iomem *sbc; struct device *dev; int irq; struct clk *clk; @@ -28760,7 +29067,14 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- struct crypto_engine *crypt_engine_hash; struct crypto_engine *crypt_engine_crypto; -@@ -268,7 +298,8 @@ +@@ -262,13 +320,15 @@ + + union { + struct skcipher_engine_alg skcipher; ++ struct aead_engine_alg aead; + struct ahash_engine_alg ahash; + } alg; + }; enum aspeed_version { AST2500_VERSION = 5, @@ -28770,21 +29084,31 @@ diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed- }; #define ast_hace_write(hace, val, offset) \ -@@ -280,5 +311,11 @@ +@@ -276,9 +336,21 @@ + #define ast_hace_read(hace, offset) \ + readl((hace)->regs + (offset)) + ++#define ast_sbc_write(hace, val, offset) \ ++ writel((val), (hace)->sbc + (offset)) ++#define ast_sbc_read(hace, offset) \ ++ readl((hace)->sbc + (offset)) ++ + void aspeed_register_hace_hash_algs(struct aspeed_hace_dev *hace_dev); void aspeed_unregister_hace_hash_algs(struct aspeed_hace_dev *hace_dev); void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev); ++void aspeed_register_hace_aead_algs(struct aspeed_hace_dev *hace_dev); ++void aspeed_register_hace_vault_key(struct aspeed_hace_dev *hace_dev); void aspeed_unregister_hace_crypto_algs(struct aspeed_hace_dev *hace_dev); +int aspeed_hace_hash_init(struct aspeed_hace_dev *hace_dev); +void aspeed_hace_hash_remove(struct aspeed_hace_dev *hace_dev); +int aspeed_hace_crypto_init(struct aspeed_hace_dev *hace_dev); +void aspeed_hace_crypto_remove(struct aspeed_hace_dev *hace_dev); -+int find_dummy_key(const char *key, int keylen); +int aspeed_hace_reset(struct aspeed_hace_dev *dev); #endif diff --git a/drivers/crypto/aspeed/aspeed-rsss-hash.c b/drivers/crypto/aspeed/aspeed-rsss-hash.c --- a/drivers/crypto/aspeed/aspeed-rsss-hash.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-rsss-hash.c 2025-12-23 10:16:21.140032401 +0000 ++++ b/drivers/crypto/aspeed/aspeed-rsss-hash.c 2026-09-09 15:51:44.737237784 +0000 @@ -0,0 +1,901 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -29689,8 +30013,8 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-hash.c b/drivers/crypto/aspeed/as +} diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/aspeed-rsss-rsa.c --- a/drivers/crypto/aspeed/aspeed-rsss-rsa.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-rsss-rsa.c 2025-12-23 10:16:21.140032401 +0000 -@@ -0,0 +1,608 @@ ++++ b/drivers/crypto/aspeed/aspeed-rsss-rsa.c 2026-09-09 15:51:44.737237784 +0000 +@@ -0,0 +1,575 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023 Aspeed Technology Inc. @@ -29942,7 +30266,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + cipher = crypto_akcipher_reqtfm(req); + ctx = akcipher_tfm_ctx(cipher); + -+ if (!ctx->n || !ctx->n_sz) { ++ if (!ctx->n_sz) { + dev_err(rsss_dev->dev, "%s: key n is not set\n", __func__); + return -EINVAL; + } @@ -29966,7 +30290,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + req->dst_len = nm / 8; + + if (ctx->enc) { -+ if (!ctx->e || !ctx->e_sz) { ++ if (!ctx->e_sz) { + dev_err(rsss_dev->dev, "%s: key e is not set\n", + __func__); + return -EINVAL; @@ -29976,7 +30300,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + ctx->e, ctx->e_sz, + ASPEED_RSA_EXP_MODE); + } else { -+ if (!ctx->d || !ctx->d_sz) { ++ if (!ctx->d_sz) { + dev_err(rsss_dev->dev, "%s: key d is not set\n", + __func__); + return -EINVAL; @@ -30034,18 +30358,11 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + return aspeed_rsa_handle_queue(rsss_dev, req); +} + -+static u8 *aspeed_rsa_key_copy(u8 *src, size_t len) -+{ -+ return kmemdup(src, len, GFP_KERNEL); -+} -+ +static int aspeed_rsa_set_n(struct aspeed_rsa_ctx *ctx, u8 *value, + size_t len) +{ + ctx->n_sz = len; -+ ctx->n = aspeed_rsa_key_copy(value, len); -+ if (!ctx->n) -+ return -ENOMEM; ++ memcpy(ctx->n, value, len); + + return 0; +} @@ -30054,9 +30371,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + size_t len) +{ + ctx->e_sz = len; -+ ctx->e = aspeed_rsa_key_copy(value, len); -+ if (!ctx->e) -+ return -ENOMEM; ++ memcpy(ctx->e, value, len); + + return 0; +} @@ -30065,23 +30380,11 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + size_t len) +{ + ctx->d_sz = len; -+ ctx->d = aspeed_rsa_key_copy(value, len); -+ if (!ctx->d) -+ return -ENOMEM; ++ memcpy(ctx->d, value, len); + + return 0; +} + -+static void aspeed_rsa_key_free(struct aspeed_rsa_ctx *ctx) -+{ -+ kfree_sensitive(ctx->n); -+ kfree_sensitive(ctx->e); -+ kfree_sensitive(ctx->d); -+ ctx->n_sz = 0; -+ ctx->e_sz = 0; -+ ctx->d_sz = 0; -+} -+ +static int aspeed_rsa_setkey(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen, int priv) +{ @@ -30109,29 +30412,17 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp + return 0; + + hexdump("n", (u8 *)ctx->key.n, ctx->key.n_sz); -+ ret = aspeed_rsa_set_n(ctx, (u8 *)ctx->key.n, ctx->key.n_sz); -+ if (ret) -+ goto err; ++ aspeed_rsa_set_n(ctx, (u8 *)ctx->key.n, ctx->key.n_sz); + + hexdump("e", (u8 *)ctx->key.e, ctx->key.e_sz); -+ ret = aspeed_rsa_set_e(ctx, (u8 *)ctx->key.e, ctx->key.e_sz); -+ if (ret) -+ goto err; ++ aspeed_rsa_set_e(ctx, (u8 *)ctx->key.e, ctx->key.e_sz); + + if (priv) { + hexdump("d", (u8 *)ctx->key.d, ctx->key.d_sz); -+ ret = aspeed_rsa_set_d(ctx, (u8 *)ctx->key.d, ctx->key.d_sz); -+ if (ret) -+ goto err; ++ aspeed_rsa_set_d(ctx, (u8 *)ctx->key.d, ctx->key.d_sz); + } + + return 0; -+ -+err: -+ dev_err(rsss_dev->dev, "rsss set key failed\n"); -+ aspeed_rsa_key_free(ctx); -+ -+ return ret; +} + +static int aspeed_rsa_set_pub_key(struct crypto_akcipher *tfm, @@ -30301,7 +30592,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/asp +} diff --git a/drivers/crypto/aspeed/aspeed-rsss.c b/drivers/crypto/aspeed/aspeed-rsss.c --- a/drivers/crypto/aspeed/aspeed-rsss.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-rsss.c 2025-12-23 10:16:21.140032401 +0000 ++++ b/drivers/crypto/aspeed/aspeed-rsss.c 2026-09-09 15:51:44.737237784 +0000 @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -30493,7 +30784,7 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss.c b/drivers/crypto/aspeed/aspeed- +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/aspeed/aspeed-rsss.h b/drivers/crypto/aspeed/aspeed-rsss.h --- a/drivers/crypto/aspeed/aspeed-rsss.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/crypto/aspeed/aspeed-rsss.h 2025-12-23 10:16:21.141032385 +0000 ++++ b/drivers/crypto/aspeed/aspeed-rsss.h 2026-09-09 15:51:44.738237769 +0000 @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + @@ -30704,9 +30995,9 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss.h b/drivers/crypto/aspeed/aspeed- + + struct rsa_key key; + int enc; -+ u8 *n; -+ u8 *e; -+ u8 *d; ++ u8 n[ASPEED_RSA_MAX_KEY_LEN]; ++ u8 e[ASPEED_RSA_MAX_KEY_LEN]; ++ u8 d[ASPEED_RSA_MAX_KEY_LEN]; + size_t n_sz; + size_t e_sz; + size_t d_sz; @@ -30770,8371 +31061,8319 @@ diff --git a/drivers/crypto/aspeed/aspeed-rsss.h b/drivers/crypto/aspeed/aspeed- +extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_512; + +#endif /* __ASPEED_RSSS_H__ */ -diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig ---- a/drivers/edac/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/edac/Kconfig 2025-12-23 10:16:21.149032250 +0000 -@@ -520,6 +520,15 @@ - First, ECC must be configured in the bootloader. Then, this driver - will expose error counters via the EDAC kernel framework. - -+config EDAC_AST2700 -+ tristate "Aspeed AST2700 BMC SoC" -+ depends on ARCH_ASPEED -+ help -+ Support for error detection and correction on the Aspeed AST2700 -+ -+ First, ECC must be configured in the bootloader. Then, this driver -+ will expose error counters via the EDAC kernel framework. -+ - config EDAC_BLUEFIELD - tristate "Mellanox BlueField Memory ECC" - depends on ARM64 && ((MELLANOX_PLATFORM && ACPI) || COMPILE_TEST) -diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c ---- a/drivers/edac/altera_edac.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/edac/altera_edac.c 2025-12-23 10:16:21.149032250 +0000 -@@ -128,7 +128,6 @@ - - ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL); - if (!ptemp) { -- dma_free_coherent(mci->pdev, 16, ptemp, dma_handle); - edac_printk(KERN_ERR, EDAC_MC, - "Inject: Buffer Allocation error\n"); - return -ENOMEM; -diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c ---- a/drivers/edac/edac_mc_sysfs.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/edac/edac_mc_sysfs.c 2025-12-23 10:16:21.151032217 +0000 -@@ -305,6 +305,14 @@ - channel_dimm_label_show, channel_dimm_label_store, 10); - DEVICE_CHANNEL(ch11_dimm_label, S_IRUGO | S_IWUSR, - channel_dimm_label_show, channel_dimm_label_store, 11); -+DEVICE_CHANNEL(ch12_dimm_label, S_IRUGO | S_IWUSR, -+ channel_dimm_label_show, channel_dimm_label_store, 12); -+DEVICE_CHANNEL(ch13_dimm_label, S_IRUGO | S_IWUSR, -+ channel_dimm_label_show, channel_dimm_label_store, 13); -+DEVICE_CHANNEL(ch14_dimm_label, S_IRUGO | S_IWUSR, -+ channel_dimm_label_show, channel_dimm_label_store, 14); -+DEVICE_CHANNEL(ch15_dimm_label, S_IRUGO | S_IWUSR, -+ channel_dimm_label_show, channel_dimm_label_store, 15); - - /* Total possible dynamic DIMM Label attribute file table */ - static struct attribute *dynamic_csrow_dimm_attr[] = { -@@ -320,6 +328,10 @@ - &dev_attr_legacy_ch9_dimm_label.attr.attr, - &dev_attr_legacy_ch10_dimm_label.attr.attr, - &dev_attr_legacy_ch11_dimm_label.attr.attr, -+ &dev_attr_legacy_ch12_dimm_label.attr.attr, -+ &dev_attr_legacy_ch13_dimm_label.attr.attr, -+ &dev_attr_legacy_ch14_dimm_label.attr.attr, -+ &dev_attr_legacy_ch15_dimm_label.attr.attr, - NULL - }; - -@@ -348,6 +360,14 @@ - channel_ce_count_show, NULL, 10); - DEVICE_CHANNEL(ch11_ce_count, S_IRUGO, - channel_ce_count_show, NULL, 11); -+DEVICE_CHANNEL(ch12_ce_count, S_IRUGO, -+ channel_ce_count_show, NULL, 12); -+DEVICE_CHANNEL(ch13_ce_count, S_IRUGO, -+ channel_ce_count_show, NULL, 13); -+DEVICE_CHANNEL(ch14_ce_count, S_IRUGO, -+ channel_ce_count_show, NULL, 14); -+DEVICE_CHANNEL(ch15_ce_count, S_IRUGO, -+ channel_ce_count_show, NULL, 15); - - /* Total possible dynamic ce_count attribute file table */ - static struct attribute *dynamic_csrow_ce_count_attr[] = { -@@ -363,6 +383,10 @@ - &dev_attr_legacy_ch9_ce_count.attr.attr, - &dev_attr_legacy_ch10_ce_count.attr.attr, - &dev_attr_legacy_ch11_ce_count.attr.attr, -+ &dev_attr_legacy_ch12_ce_count.attr.attr, -+ &dev_attr_legacy_ch13_ce_count.attr.attr, -+ &dev_attr_legacy_ch14_ce_count.attr.attr, -+ &dev_attr_legacy_ch15_ce_count.attr.attr, - NULL - }; - -diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c ---- a/drivers/edac/i10nm_base.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/edac/i10nm_base.c 2025-12-23 10:16:21.152032200 +0000 -@@ -967,6 +967,15 @@ - return !!GET_BITFIELD(mcmtr, 2, 2); - } - -+static bool i10nm_channel_disabled(struct skx_imc *imc, int chan) -+{ -+ u32 mcmtr = I10NM_GET_MCMTR(imc, chan); -+ -+ edac_dbg(1, "mc%d ch%d mcmtr reg %x\n", imc->mc, chan, mcmtr); -+ -+ return (mcmtr == ~0 || GET_BITFIELD(mcmtr, 18, 18)); -+} -+ - static int i10nm_get_dimm_config(struct mem_ctl_info *mci, - struct res_config *cfg) - { -@@ -980,6 +989,11 @@ - if (!imc->mbase) - continue; - -+ if (i10nm_channel_disabled(imc, i)) { -+ edac_dbg(1, "mc%d ch%d is disabled.\n", imc->mc, i); -+ continue; -+ } -+ - ndimms = 0; - - if (res_cfg->type != GNR) -diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c ---- a/drivers/fsi/fsi-master-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/fsi/fsi-master-aspeed.c 2025-12-23 10:16:20.956035485 +0000 -@@ -3,6 +3,7 @@ - // FSI master driver for AST2600 - - #include -+#include - #include - #include - #include -@@ -24,9 +25,14 @@ - struct device *dev; - void __iomem *base; - struct clk *clk; -+ struct reset_control *rst; - struct gpio_desc *cfam_reset_gpio; - }; - -+struct aspeed_fsi_match_data { -+ bool sup_ahb_access; -+}; -+ - #define to_fsi_master_aspeed(m) \ - container_of(m, struct fsi_master_aspeed, master) - -@@ -60,6 +66,8 @@ - #define OPB1_READ_ORDER2 0x60 - - #define OPB_RETRY_COUNTER 0x64 -+#define OPB_ACCESS_CTRL_REG BIT(18) -+#define OPB_ACCESS_CPU_BRIDGE BIT(19) - - /* OPBn_STATUS */ - #define STATUS_HALFWORD_ACK BIT(0) -@@ -539,6 +547,7 @@ - struct fsi_master_aspeed *aspeed; - int rc, links, reg; - __be32 raw; -+ const struct aspeed_fsi_match_data *match_data; - - rc = tacoma_cabled_fsi_fixup(&pdev->dev); - if (rc) { -@@ -558,16 +567,22 @@ - goto err_free_aspeed; - } - -+ aspeed->rst = devm_reset_control_get_shared(&pdev->dev, NULL); -+ if (IS_ERR(aspeed->rst)) -+ dev_warn(aspeed->dev, "couldn't get reset\n"); -+ else -+ reset_control_deassert(aspeed->rst); -+ - aspeed->clk = devm_clk_get(aspeed->dev, NULL); - if (IS_ERR(aspeed->clk)) { - dev_err(aspeed->dev, "couldn't get clock\n"); - rc = PTR_ERR(aspeed->clk); -- goto err_free_aspeed; -+ goto err_reset; - } - rc = clk_prepare_enable(aspeed->clk); - if (rc) { - dev_err(aspeed->dev, "couldn't enable clock\n"); -- goto err_free_aspeed; -+ goto err_reset; - } - - rc = setup_cfam_reset(aspeed); -@@ -580,7 +595,12 @@ - aspeed->base + OPB_IRQ_MASK); - - /* TODO: determine an appropriate value */ -- writel(0x10, aspeed->base + OPB_RETRY_COUNTER); -+ match_data = of_device_get_match_data(&pdev->dev); -+ if (match_data->sup_ahb_access) -+ writel(0x10 | OPB_ACCESS_CTRL_REG | OPB_ACCESS_CPU_BRIDGE, -+ aspeed->base + OPB_RETRY_COUNTER); -+ else -+ writel(0x10, aspeed->base + OPB_RETRY_COUNTER); - - writel(ctrl_base, aspeed->base + OPB_CTRL_BASE); - writel(fsi_base, aspeed->base + OPB_FSI_BASE); -@@ -641,6 +661,9 @@ - - err_release: - clk_disable_unprepare(aspeed->clk); -+err_reset: -+ if (!IS_ERR(aspeed->rst)) -+ reset_control_assert(aspeed->rst); - err_free_aspeed: - kfree(aspeed); - return rc; -@@ -652,10 +675,21 @@ - - fsi_master_unregister(&aspeed->master); - clk_disable_unprepare(aspeed->clk); -+ if (!IS_ERR(aspeed->rst)) -+ reset_control_assert(aspeed->rst); - } - -+static const struct aspeed_fsi_match_data ast2600_match_data = { -+ .sup_ahb_access = 0, -+}; -+ -+static const struct aspeed_fsi_match_data ast2700_match_data = { -+ .sup_ahb_access = 1, -+}; -+ - static const struct of_device_id fsi_master_aspeed_match[] = { -- { .compatible = "aspeed,ast2600-fsi-master" }, -+ { .compatible = "aspeed,ast2600-fsi-master", .data = &ast2600_match_data }, -+ { .compatible = "aspeed,ast2700-fsi-master", .data = &ast2700_match_data }, - { }, - }; - MODULE_DEVICE_TABLE(of, fsi_master_aspeed_match); -diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig ---- a/drivers/gpio/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpio/Kconfig 2025-12-23 10:16:09.425228786 +0000 -@@ -180,6 +180,14 @@ - help - Say Y here to support Aspeed AST2500 SGPIO functionality. - -+config GPIO_ASPEED_LTPI -+ bool "Aspeed LTPI GPIO support" -+ depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO -+ select GPIO_GENERIC -+ select GPIOLIB_IRQCHIP -+ help -+ Say Y here to support Aspeed AST2700 LTPI GPIO functionality. -+ - config GPIO_ATH79 - tristate "Atheros AR71XX/AR724X/AR913X GPIO support" - default y if ATH79 -diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile ---- a/drivers/gpio/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpio/Makefile 2025-12-23 10:16:13.585159025 +0000 -@@ -36,6 +36,7 @@ - obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o - obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o - obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o -+obj-$(CONFIG_GPIO_ASPEED_LTPI) += gpio-aspeed-ltpi.o - obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o - obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o - obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o -diff --git a/drivers/gpio/gpio-aspeed-ltpi.c b/drivers/gpio/gpio-aspeed-ltpi.c ---- a/drivers/gpio/gpio-aspeed-ltpi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/gpio/gpio-aspeed-ltpi.c 2025-12-23 10:16:21.060033742 +0000 -@@ -0,0 +1,469 @@ -+// SPDX-License-Identifier: GPL-2.0 +diff --git a/drivers/edac/edac_ast2700.c b/drivers/edac/edac_ast2700.c +--- a/drivers/edac/edac_ast2700.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/edac/edac_ast2700.c 2026-09-09 15:51:44.378243209 +0000 +@@ -0,0 +1,354 @@ ++// SPDX-License-Identifier: GPL-2.0+ +/* -+ * Copyright (c) 2024 ASPEED -+ * -+ * Author: Billy Tsai ++ * Copyright 2018, 2019 Cisco Systems + */ + -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++#include +#include ++#include ++#include +#include -+#include -+#include -+#include ++#include ++#include ++#include ++#include ++#include "edac_module.h" + -+#define LTPI_GPIO_IRQ_STS_BASE 0x200 -+#define LTPI_GPIO_IRQ_STS_OFFSET(x) (LTPI_GPIO_IRQ_STS_BASE + (x) * 0x4) -+#define LTPI_GPIO_CTRL_REG_BASE 0x0 -+#define LTPI_GPIO_CTRL_REG_OFFSET(x) (LTPI_GPIO_CTRL_REG_BASE + (x) * 0x4) -+#define LTPI_GPIO_OUT_DATA BIT(0) -+#define LTPI_GPIO_IRQ_EN BIT(2) -+#define LTPI_GPIO_IRQ_TYPE0 BIT(3) -+#define LTPI_GPIO_IRQ_TYPE1 BIT(4) -+#define LTPI_GPIO_IRQ_TYPE2 BIT(5) -+#define LTPI_GPIO_RST_TOLERANCE BIT(6) -+#define LTPI_GPIO_IRQ_STS BIT(12) -+#define LTPI_GPIO_IN_DATA BIT(13) ++#define DRV_NAME "aspeed-edac" + -+static inline u32 field_get(u32 _mask, u32 _val) -+{ -+ return (((_val) & (_mask)) >> (ffs(_mask) - 1)); -+} ++#define DRAMC_PROT 0x00 /* protection key register */ ++#define DRAMC_INT_STS 0x04 /* interrupt status register */ ++#define INT_STS_ECC_REC BIT(5) /* ECC recoverable error interrupt */ ++#define INT_STS_ECC_ERR BIT(4) /* ECC error interrupt */ ++#define DRAMC_INT_CLR 0x08 /* interrupt clear register */ ++#define DRAMC_INT_MASK 0x0c /* interrupt mask register */ ++#define DRAMC_MCFG 0x10 /* main configuration register */ ++#define MCFG_ECC_ENABLE BIT(6) ++#define MCFG_DRAM_SIZE_MASK GENMASK(5, 4) /* 2=1GB, 3=2GB, 4=4GB, 5=8GB */ ++#define MCFG_DRAM_SIZE_SHIFT (2) ++#define MCFG_DRAM_TYPE BIT(0) /* 0=DDR4, 1=DDR5 */ + -+static inline u32 field_prep(u32 _mask, u32 _val) -+{ -+ return (((_val) << (ffs(_mask) - 1)) & (_mask)); -+} ++#define DRAMC_ECC_STS 0x78 /* ECC status register */ ++#define ECC_STS_REC_CNT_MASK GENMASK(15, 8) /* recoverable error count */ ++#define ECC_STS_REC_CNT_SHIFT (8) ++#define ECC_STS_UNREC_CNT_MASK GENMASK(7, 0) /* unrecoverable error count */ ++#define ECC_STS_UNREC_CNT_SHIFT (0) ++#define DRAMC_ECC_FAIL_ADDR 0x7c /* ECC fail address register */ + -+static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) -+{ -+ iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); -+} ++static struct regmap *aspeed_regmap; + -+static inline void ast_clr_bits(void __iomem *addr, u32 mask) ++static int regmap_reg_write(void *context, unsigned int reg, unsigned int val) +{ -+ iowrite32((ioread32(addr) & ~(mask)), addr); -+} ++ void __iomem *regs = (void __iomem *)context; + -+struct aspeed_ltpi_gpio { -+ struct gpio_chip chip; -+ struct device *dev; -+ raw_spinlock_t lock; -+ void __iomem *base; -+ int irq; -+}; ++ writel(val, regs + reg); + -+static int aspeed_ltpi_gpio_init_valid_mask(struct gpio_chip *gc, -+ unsigned long *valid_mask, -+ unsigned int ngpios) -+{ -+ bitmap_set(valid_mask, 0, ngpios); + return 0; +} + -+static void aspeed_ltpi_gpio_irq_init_valid_mask(struct gpio_chip *gc, -+ unsigned long *valid_mask, -+ unsigned int ngpios) ++static int regmap_reg_read(void *context, unsigned int reg, unsigned int *val) +{ -+ unsigned int i; ++ void __iomem *regs = (void __iomem *)context; + -+ /* input GPIOs are even bits */ -+ for (i = 0; i < ngpios; i++) { -+ if (i % 2) -+ clear_bit(i, valid_mask); -+ } ++ *val = readl(regs + reg); ++ ++ return 0; +} + -+static int aspeed_ltpi_gpio_irq_init_hw(struct gpio_chip *gc) ++static bool regmap_is_volatile(struct device *dev, unsigned int reg) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ void __iomem *addr; -+ unsigned long flags; -+ int i; ++ return 1; ++} + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++static const struct regmap_config aspeed_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = DRAMC_ECC_FAIL_ADDR, ++ .reg_write = regmap_reg_write, ++ .reg_read = regmap_reg_read, ++ .volatile_reg = regmap_is_volatile, ++ .fast_io = true, ++}; + -+ for (i = 0; i < (gc->ngpio >> 1); i++) { -+ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(i); -+ ast_clr_bits(addr, LTPI_GPIO_IRQ_EN | LTPI_GPIO_IRQ_TYPE0 | -+ LTPI_GPIO_IRQ_TYPE1 | -+ LTPI_GPIO_IRQ_TYPE2); -+ ast_write_bits(addr, LTPI_GPIO_IRQ_STS, 1); -+ } ++static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) ++{ ++ struct csrow_info *csrow = mci->csrows[0]; ++ u32 page, offset, syndrome; + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ if (!rec_cnt) ++ return; + -+ return 0; -+} ++ /* report first few errors (if there are) */ ++ /* note: no addresses are recorded */ ++ if (rec_cnt > 1) { ++ /* page, offset and syndrome are not available */ ++ page = 0; ++ offset = 0; ++ syndrome = 0; ++ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, rec_cnt - 1, ++ page, offset, syndrome, 0, 0, -1, ++ "address(es) not available", ""); ++ } + -+static bool aspeed_ltpi_gpio_is_input(unsigned int offset) -+{ -+ return !(offset % 2); ++ /* report last error */ ++ /* note: rec_addr is the last recoverable error addr */ ++ page = rec_addr >> PAGE_SHIFT; ++ offset = rec_addr & ~PAGE_MASK; ++ /* syndrome is not available */ ++ syndrome = 0; ++ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, ++ csrow->first_page + page, offset, syndrome, ++ 0, 0, -1, "", ""); +} + -+static int aspeed_ltpi_gpio_get(struct gpio_chip *gc, unsigned int offset) ++static void count_un_rec(struct mem_ctl_info *mci, u8 un_rec_cnt, ++ u32 un_rec_addr) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ void __iomem const *addr = -+ gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); -+ unsigned long flags; -+ u32 mask; -+ int rc = 0; -+ -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++ struct csrow_info *csrow = mci->csrows[0]; ++ u32 page, offset, syndrome; + -+ mask = aspeed_ltpi_gpio_is_input(offset) ? LTPI_GPIO_IN_DATA : -+ LTPI_GPIO_OUT_DATA; -+ rc = !!(field_get(mask, ioread32(addr))); ++ if (!un_rec_cnt) ++ return; + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ /* report 1. error */ ++ /* note: un_rec_addr is the first unrecoverable error addr */ ++ page = un_rec_addr >> PAGE_SHIFT; ++ offset = un_rec_addr & ~PAGE_MASK; ++ /* syndrome is not available */ ++ syndrome = 0; ++ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, ++ csrow->first_page + page, offset, syndrome, ++ 0, 0, -1, "", ""); + -+ return rc; ++ /* report further errors (if there are) */ ++ /* note: no addresses are recorded */ ++ if (un_rec_cnt > 1) { ++ /* page, offset and syndrome are not available */ ++ page = 0; ++ offset = 0; ++ syndrome = 0; ++ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, un_rec_cnt - 1, ++ page, offset, syndrome, 0, 0, -1, ++ "address(es) not available", ""); ++ } +} + -+static int ltpi_gpio_set_value(struct gpio_chip *gc, unsigned int offset, -+ int val) ++static irqreturn_t mcr_isr(int irq, void *arg) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ void __iomem *addr = -+ gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); -+ u32 reg = 0; ++ struct mem_ctl_info *mci = arg; ++ u32 reg, ecc_sts, ecc_fail_addr; ++ u16 rec_cnt, un_rec_cnt; + -+ if (aspeed_ltpi_gpio_is_input(offset)) -+ return -EINVAL; -+ -+ reg = ioread32(addr); ++ regmap_read(aspeed_regmap, DRAMC_INT_STS, ®); + -+ if (val) -+ reg |= LTPI_GPIO_OUT_DATA; -+ else -+ reg &= ~LTPI_GPIO_OUT_DATA; ++ regmap_read(aspeed_regmap, DRAMC_ECC_STS, &ecc_sts); + -+ iowrite32(reg, addr); ++ /* collect data about recoverable and unrecoverable errors */ ++ rec_cnt = (ecc_sts & ECC_STS_REC_CNT_MASK) >> ECC_STS_REC_CNT_SHIFT; ++ un_rec_cnt = (ecc_sts & ECC_STS_UNREC_CNT_MASK) >> ECC_STS_UNREC_CNT_SHIFT; + -+ return 0; -+} ++ regmap_read(aspeed_regmap, DRAMC_ECC_FAIL_ADDR, &ecc_fail_addr); + -+static void aspeed_ltpi_gpio_set(struct gpio_chip *gc, unsigned int offset, -+ int val) -+{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ unsigned long flags; ++ /* clear interrupt flags */ ++ regmap_update_bits(aspeed_regmap, DRAMC_INT_CLR, ++ reg, reg); + -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ ltpi_gpio_set_value(gc, offset, val); -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+} ++ /* process recoverable and unrecoverable errors */ ++ count_rec(mci, rec_cnt, ecc_fail_addr); ++ count_un_rec(mci, un_rec_cnt, ecc_fail_addr); + -+static int aspeed_ltpi_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) -+{ -+ return aspeed_ltpi_gpio_is_input(offset) ? 0 : -EINVAL; ++ return IRQ_HANDLED; +} + -+static int aspeed_ltpi_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, -+ int val) ++static int config_irq(void *ctx, struct platform_device *pdev) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ unsigned long flags; ++ int irq; + int rc; + -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ rc = ltpi_gpio_set_value(gc, offset, val); -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ return rc; -+} -+ -+static int aspeed_ltpi_gpio_get_direction(struct gpio_chip *gc, -+ unsigned int offset) -+{ -+ return !!aspeed_ltpi_gpio_is_input(offset); -+} ++ /* register interrupt handler */ ++ irq = platform_get_irq(pdev, 0); ++ dev_dbg(&pdev->dev, "got irq %d\n", irq); ++ if (irq < 0) ++ return irq; + -+static void irqd_to_aspeed_ltpi_gpio_data(struct irq_data *d, -+ struct aspeed_ltpi_gpio **gpio, -+ int *offset) -+{ -+ struct aspeed_ltpi_gpio *internal; ++ rc = devm_request_irq(&pdev->dev, irq, mcr_isr, IRQF_TRIGGER_HIGH, ++ DRV_NAME, ctx); ++ if (rc) { ++ dev_err(&pdev->dev, "unable to request irq %d\n", irq); ++ return rc; ++ } + -+ *offset = irqd_to_hwirq(d); -+ internal = irq_data_get_irq_chip_data(d); -+ WARN_ON(!internal); ++ /* enable interrupts */ ++ regmap_clear_bits(aspeed_regmap, DRAMC_INT_MASK, ++ INT_STS_ECC_REC | INT_STS_ECC_ERR); + -+ *gpio = internal; ++ return 0; +} + -+static void aspeed_ltpi_gpio_irq_ack(struct irq_data *d) ++static int init_csrows(struct mem_ctl_info *mci) +{ -+ struct aspeed_ltpi_gpio *gpio; -+ unsigned long flags; -+ void __iomem *status_addr; -+ int offset; ++ struct csrow_info *csrow = mci->csrows[0]; ++ u32 nr_pages, dram_type; ++ struct dimm_info *dimm; ++ struct device_node *np; ++ struct resource r; ++ u32 reg04; ++ int rc; + -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ pr_info("%s: initializing csrows\n", DRV_NAME); + -+ status_addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ /* retrieve info about physical memory from device tree */ ++ np = of_find_node_by_name(NULL, "memory"); ++ if (!np) { ++ dev_err(mci->pdev, "dt: missing /memory node\n"); ++ return -ENODEV; ++ } + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++ rc = of_address_to_resource(np, 0, &r); + -+ ast_write_bits(status_addr, LTPI_GPIO_IRQ_STS, 1); ++ of_node_put(np); + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+} ++ if (rc) { ++ dev_err(mci->pdev, "dt: failed requesting resource for /memory node\n"); ++ return rc; ++ } + -+static void aspeed_ltpi_gpio_irq_set_mask(struct irq_data *d, bool set) -+{ -+ struct aspeed_ltpi_gpio *gpio; -+ unsigned long flags; -+ void __iomem *addr; -+ int offset; ++ dev_dbg(mci->pdev, "dt: /memory node resources: first page %pR, PAGE_SHIFT macro=0x%x\n", ++ &r, PAGE_SHIFT); + -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); -+ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ csrow->first_page = r.start >> PAGE_SHIFT; ++ nr_pages = resource_size(&r) >> PAGE_SHIFT; ++ csrow->last_page = csrow->first_page + nr_pages - 1; + -+ /* Unmasking the IRQ */ -+ if (set) -+ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); ++ regmap_read(aspeed_regmap, DRAMC_MCFG, ®04); ++ dram_type = (reg04 & MCFG_DRAM_TYPE) ? MEM_DDR5 : MEM_DDR4; + -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ if (set) -+ ast_write_bits(addr, LTPI_GPIO_IRQ_EN, 1); -+ else -+ ast_clr_bits(addr, LTPI_GPIO_IRQ_EN); -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ dimm = csrow->channels[0]->dimm; ++ dimm->mtype = dram_type; ++ dimm->edac_mode = EDAC_SECDED; ++ dimm->nr_pages = nr_pages / csrow->nr_channels; + -+ /* Masking the IRQ */ -+ if (!set) -+ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); -+} ++ dev_dbg(mci->pdev, "initialized dimm with first_page=0x%lx and nr_pages=0x%x\n", ++ csrow->first_page, nr_pages); + -+static void aspeed_ltpi_gpio_irq_mask(struct irq_data *d) -+{ -+ aspeed_ltpi_gpio_irq_set_mask(d, false); ++ return 0; +} + -+static void aspeed_ltpi_gpio_irq_unmask(struct irq_data *d) ++static int aspeed_probe(struct platform_device *pdev) +{ -+ aspeed_ltpi_gpio_irq_set_mask(d, true); -+} ++ struct device *dev = &pdev->dev; ++ struct edac_mc_layer layers[2]; ++ struct mem_ctl_info *mci; ++ void __iomem *regs; ++ //u32 reg04; ++ u32 reg; ++ int rc; + -+static int aspeed_ltpi_gpio_set_type(struct irq_data *d, unsigned int type) -+{ -+ u32 type0 = 0; -+ u32 type1 = 0; -+ u32 type2 = 0; -+ irq_flow_handler_t handler; -+ struct aspeed_ltpi_gpio *gpio; -+ unsigned long flags; -+ void __iomem *addr; -+ int offset; ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); + -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); -+ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ aspeed_regmap = devm_regmap_init(dev, NULL, (__force void *)regs, ++ &aspeed_regmap_config); ++ if (IS_ERR(aspeed_regmap)) ++ return PTR_ERR(aspeed_regmap); + -+ switch (type & IRQ_TYPE_SENSE_MASK) { -+ case IRQ_TYPE_EDGE_BOTH: -+ type2 = 1; -+ fallthrough; -+ case IRQ_TYPE_EDGE_RISING: -+ type0 = 1; -+ fallthrough; -+ case IRQ_TYPE_EDGE_FALLING: -+ handler = handle_edge_irq; -+ break; -+ case IRQ_TYPE_LEVEL_HIGH: -+ type0 = 1; -+ fallthrough; -+ case IRQ_TYPE_LEVEL_LOW: -+ type1 = 1; -+ handler = handle_level_irq; -+ break; -+ default: -+ return -EINVAL; ++ /* bail out if ECC mode is not configured */ ++ regmap_read(aspeed_regmap, DRAMC_MCFG, ®); ++ if (!(reg & MCFG_ECC_ENABLE)) { ++ dev_err(&pdev->dev, "ECC mode is not configured in u-boot\n"); ++ return -EPERM; + } + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++ edac_op_state = EDAC_OPSTATE_INT; + -+ ast_write_bits(addr, LTPI_GPIO_IRQ_TYPE2, type2); -+ ast_write_bits(addr, LTPI_GPIO_IRQ_TYPE1, type1); -+ ast_write_bits(addr, LTPI_GPIO_IRQ_TYPE0, type0); ++ /* allocate & init EDAC MC data structure */ ++ layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; ++ layers[0].size = 1; ++ layers[0].is_virt_csrow = true; ++ layers[1].type = EDAC_MC_LAYER_CHANNEL; ++ layers[1].size = 1; ++ layers[1].is_virt_csrow = false; + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); ++ if (!mci) ++ return -ENOMEM; ++ ++ mci->pdev = &pdev->dev; ++ mci->mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_DDR5; ++ mci->edac_ctl_cap = EDAC_FLAG_SECDED; ++ mci->edac_cap = EDAC_FLAG_SECDED; ++ mci->scrub_cap = SCRUB_FLAG_HW_SRC; ++ mci->scrub_mode = SCRUB_HW_SRC; ++ mci->mod_name = DRV_NAME; ++ mci->ctl_name = "MIC"; ++ mci->dev_name = dev_name(&pdev->dev); ++ ++ rc = init_csrows(mci); ++ if (rc) { ++ dev_err(&pdev->dev, "failed to init csrows\n"); ++ goto probe_exit02; ++ } ++ ++ platform_set_drvdata(pdev, mci); ++ ++ /* register with edac core */ ++ rc = edac_mc_add_mc(mci); ++ if (rc) { ++ dev_err(&pdev->dev, "failed to register with EDAC core\n"); ++ goto probe_exit02; ++ } ++ ++ /* register interrupt handler and enable interrupts */ ++ rc = config_irq(mci, pdev); ++ if (rc) { ++ dev_err(&pdev->dev, "failed setting up irq\n"); ++ goto probe_exit01; ++ } + -+ irq_set_handler_locked(d, handler); + return 0; ++ ++probe_exit01: ++ edac_mc_del_mc(&pdev->dev); ++probe_exit02: ++ edac_mc_free(mci); ++ return rc; +} + -+static void aspeed_ltpi_gpio_irq_handler(struct irq_desc *desc) ++static void aspeed_remove(struct platform_device *pdev) +{ -+ struct gpio_chip *gc = irq_desc_get_handler_data(desc); -+ struct irq_chip *ic = irq_desc_get_chip(desc); -+ struct aspeed_ltpi_gpio const *gpio = gpiochip_get_data(gc); -+ unsigned int i, p, banks; -+ unsigned long reg; -+ void __iomem const *addr; ++ struct mem_ctl_info *mci; + -+ chained_irq_enter(ic, desc); ++ /* disable interrupts */ ++ regmap_update_bits(aspeed_regmap, DRAMC_INT_MASK, ++ INT_STS_ECC_REC | INT_STS_ECC_ERR, ++ INT_STS_ECC_REC | INT_STS_ECC_ERR); + -+ banks = DIV_ROUND_UP(gpio->chip.ngpio >> 1, 32); -+ for (i = 0; i < banks; i++) { -+ addr = gpio->base + LTPI_GPIO_IRQ_STS_OFFSET(i); ++ /* free resources */ ++ mci = edac_mc_del_mc(&pdev->dev); ++ if (mci) ++ edac_mc_free(mci); ++} + -+ reg = ioread32(addr); -+ -+ for_each_set_bit(p, ®, 32) -+ generic_handle_domain_irq(gc->irq.domain, -+ (i * 32 + p) * 2); -+ } -+ chained_irq_exit(ic, desc); -+} -+ -+static void aspeed_ltpi_gpio_irq_print_chip(struct irq_data *d, -+ struct seq_file *p) -+{ -+ struct aspeed_ltpi_gpio *gpio; -+ int offset; -+ -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); -+ seq_printf(p, dev_name(gpio->dev)); -+} -+ -+static const struct irq_chip aspeed_ltpi_gpio_irq_chip = { -+ .irq_ack = aspeed_ltpi_gpio_irq_ack, -+ .irq_mask = aspeed_ltpi_gpio_irq_mask, -+ .irq_unmask = aspeed_ltpi_gpio_irq_unmask, -+ .irq_set_type = aspeed_ltpi_gpio_set_type, -+ .irq_print_chip = aspeed_ltpi_gpio_irq_print_chip, -+ .flags = IRQCHIP_IMMUTABLE, -+ GPIOCHIP_IRQ_RESOURCE_HELPERS, -+}; -+ -+static int aspeed_ltpi_gpio_setup_irqs(struct aspeed_ltpi_gpio *gpio, -+ struct platform_device *pdev) -+{ -+ int rc; -+ struct gpio_irq_chip *irq; -+ -+ rc = platform_get_irq(pdev, 0); -+ if (rc < 0) -+ return rc; -+ -+ gpio->irq = rc; -+ -+ irq = &gpio->chip.irq; -+ gpio_irq_chip_set_chip(irq, &aspeed_ltpi_gpio_irq_chip); -+ irq->init_valid_mask = aspeed_ltpi_gpio_irq_init_valid_mask; -+ irq->handler = handle_bad_irq; -+ irq->init_hw = aspeed_ltpi_gpio_irq_init_hw; -+ irq->default_type = IRQ_TYPE_NONE; -+ irq->parent_handler = aspeed_ltpi_gpio_irq_handler; -+ irq->parent_handler_data = gpio; -+ irq->parents = &gpio->irq; -+ irq->num_parents = 1; -+ -+ return 0; -+} -+ -+static int aspeed_ltpi_gpio_reset_tolerance(struct gpio_chip *chip, -+ unsigned int offset, bool enable) -+{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(chip); -+ unsigned long flags; -+ void __iomem *reg; -+ -+ reg = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); -+ -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ -+ if (enable) -+ ast_write_bits(reg, LTPI_GPIO_RST_TOLERANCE, 1); -+ else -+ ast_clr_bits(reg, LTPI_GPIO_RST_TOLERANCE); -+ -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ return 0; -+} -+ -+static int aspeed_ltpi_gpio_set_config(struct gpio_chip *chip, -+ unsigned int offset, -+ unsigned long config) -+{ -+ unsigned long param = pinconf_to_config_param(config); -+ u32 arg = pinconf_to_config_argument(config); -+ -+ if (param == PIN_CONFIG_PERSIST_STATE) -+ return aspeed_ltpi_gpio_reset_tolerance(chip, offset, arg); -+ -+ return -EOPNOTSUPP; -+} -+ -+static const struct of_device_id aspeed_ltpi_gpio_of_table[] = { -+ { .compatible = "aspeed,ast2700-ltpi-gpio" }, -+ {} ++static const struct of_device_id aspeed_of_match[] = { ++ { .compatible = "aspeed,ast2700-sdram-edac" }, ++ {}, +}; + -+MODULE_DEVICE_TABLE(of, aspeed_ltpi_gpio_of_table); -+ -+static int __init aspeed_ltpi_gpio_probe(struct platform_device *pdev) -+{ -+ u32 nr_gpios; -+ struct aspeed_ltpi_gpio *gpio; -+ int rc; -+ -+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); -+ if (!gpio) -+ return -ENOMEM; -+ -+ gpio->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(gpio->base)) -+ return PTR_ERR(gpio->base); -+ -+ gpio->dev = &pdev->dev; -+ -+ rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); -+ if (rc < 0) { -+ dev_err(&pdev->dev, "Could not read ngpios property\n"); -+ return -EINVAL; -+ } -+ -+ raw_spin_lock_init(&gpio->lock); -+ -+ gpio->chip.parent = &pdev->dev; -+ gpio->chip.ngpio = nr_gpios * 2; -+ gpio->chip.init_valid_mask = aspeed_ltpi_gpio_init_valid_mask; -+ gpio->chip.direction_input = aspeed_ltpi_gpio_dir_in; -+ gpio->chip.direction_output = aspeed_ltpi_gpio_dir_out; -+ gpio->chip.get_direction = aspeed_ltpi_gpio_get_direction; -+ gpio->chip.request = NULL; -+ gpio->chip.free = NULL; -+ gpio->chip.get = aspeed_ltpi_gpio_get; -+ gpio->chip.set = aspeed_ltpi_gpio_set; -+ gpio->chip.set_config = aspeed_ltpi_gpio_set_config; -+ gpio->chip.label = dev_name(&pdev->dev); -+ gpio->chip.base = -1; -+ -+ aspeed_ltpi_gpio_setup_irqs(gpio, pdev); -+ -+ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); -+ if (rc < 0) -+ return rc; -+ -+ return 0; -+} ++MODULE_DEVICE_TABLE(of, aspeed_of_match); + -+static struct platform_driver aspeed_ltpi_gpio_driver = { -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_ltpi_gpio_of_table, ++static struct platform_driver aspeed_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = aspeed_of_match + }, ++ .probe = aspeed_probe, ++ .remove = aspeed_remove +}; ++module_platform_driver(aspeed_driver); + -+module_platform_driver_probe(aspeed_ltpi_gpio_driver, aspeed_ltpi_gpio_probe); -+MODULE_DESCRIPTION("Aspeed LTPI GPIO Driver"); -diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c ---- a/drivers/gpio/gpio-aspeed-sgpio.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpio/gpio-aspeed-sgpio.c 2025-12-23 10:16:21.056033809 +0000 -@@ -18,7 +18,51 @@ - #include - #include - --#define ASPEED_SGPIO_CTRL 0x54 -+#define SGPIO_G7_IRQ_STS_BASE 0x40 -+#define SGPIO_G7_IRQ_STS_OFFSET(x) (SGPIO_G7_IRQ_STS_BASE + (x) * 0x4) -+#define SGPIO_G7_CTRL_REG_BASE 0x80 -+#define SGPIO_G7_CTRL_REG_OFFSET(x) (SGPIO_G7_CTRL_REG_BASE + (x) * 0x4) -+#define SGPIO_G7_OUT_DATA BIT(0) -+#define SGPIO_G7_PARALLEL_OUT_DATA BIT(1) -+#define SGPIO_G7_IRQ_EN BIT(2) -+#define SGPIO_G7_IRQ_TYPE0 BIT(3) -+#define SGPIO_G7_IRQ_TYPE1 BIT(4) -+#define SGPIO_G7_IRQ_TYPE2 BIT(5) -+#define SGPIO_G7_RST_TOLERANCE BIT(6) -+#define SGPIO_G7_INPUT_MASK BIT(9) -+#define SGPIO_G7_HW_BYPASS_EN BIT(10) -+#define SGPIO_G7_HW_IN_SEL BIT(11) -+#define SGPIO_G7_IRQ_STS BIT(12) -+#define SGPIO_G7_IN_DATA BIT(13) -+#define SGPIO_G7_PARALLEL_IN_DATA BIT(14) -+#define SGPIO_G7_SERIAL_OUT_SEL GENMASK(17, 16) -+#define SGPIO_G7_PARALLEL_OUT_SEL GENMASK(19, 18) -+#define SELECT_FROM_CSR 0 -+#define SELECT_FROM_PARALLEL_IN 1 -+#define SELECT_FROM_SERIAL_IN 1 -+ -+#define BMC_CONTROL_START_INDEX 128 -+#define BMC_CONTROL_END_INDEX 143 -+ -+static inline u32 field_get(u32 _mask, u32 _val) -+{ -+ return (((_val) & (_mask)) >> (ffs(_mask) - 1)); -+} -+ -+static inline u32 field_prep(u32 _mask, u32 _val) -+{ -+ return (((_val) << (ffs(_mask) - 1)) & (_mask)); -+} -+ -+static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) -+{ -+ iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); -+} -+ -+static inline void ast_clr_bits(void __iomem *addr, u32 mask) -+{ -+ iowrite32((ioread32(addr) & ~(mask)), addr); -+} - - #define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) - #define ASPEED_SGPIO_ENABLE BIT(0) -@@ -26,6 +70,9 @@ - - struct aspeed_sgpio_pdata { - const u32 pin_mask; -+ const u16 ctrl_reg; -+ const int version; -+ const bool slave; - }; - - struct aspeed_sgpio { -@@ -35,6 +82,8 @@ - raw_spinlock_t lock; - void __iomem *base; - int irq; -+ int version; -+ const struct aspeed_sgpio_pdata *pdata; - }; - - struct aspeed_sgpio_bank { -@@ -166,19 +215,39 @@ - return !(offset % 2); - } - -+static bool aspeed_sgpios_ctrl_by_csr(unsigned int offset) -+{ -+ if (offset >= BMC_CONTROL_START_INDEX && -+ offset <= BMC_CONTROL_END_INDEX) -+ return true; -+ return false; -+} -+ - static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ const struct aspeed_sgpio_bank *bank; -+ void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); - unsigned long flags; - enum aspeed_sgpio_reg reg; - int rc = 0; - - raw_spin_lock_irqsave(&gpio->lock, flags); - -- reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; -- rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); -- -+ if (gpio->version == 7) { -+ if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) -+ reg = aspeed_sgpio_is_input(offset) ? -+ SGPIO_G7_PARALLEL_IN_DATA : -+ SGPIO_G7_PARALLEL_OUT_DATA; -+ else -+ reg = aspeed_sgpio_is_input(offset) ? SGPIO_G7_IN_DATA : -+ SGPIO_G7_OUT_DATA; -+ rc = !!(field_get(reg, ioread32(addr))); -+ } else { -+ bank = to_bank(offset); -+ reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; -+ rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); -+ } - raw_spin_unlock_irqrestore(&gpio->lock, flags); - - return rc; -@@ -211,6 +280,38 @@ - return 0; - } - -+static int sgpio_g7_set_value(struct gpio_chip *gc, unsigned int offset, -+ int val) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ u32 reg = 0, out_data; -+ -+ if (aspeed_sgpio_is_input(offset)) -+ return -EINVAL; -+ -+ if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) { -+ // Ensure the parallel out value control by the software. -+ ast_write_bits(addr, SGPIO_G7_PARALLEL_OUT_SEL, -+ SELECT_FROM_CSR); -+ out_data = SGPIO_G7_PARALLEL_OUT_DATA; -+ } else { -+ // Ensure the serial out value control by the software. -+ ast_write_bits(addr, SGPIO_G7_SERIAL_OUT_SEL, SELECT_FROM_CSR); -+ out_data = SGPIO_G7_OUT_DATA; -+ } -+ reg = ioread32(addr); -+ -+ if (val) -+ reg |= out_data; -+ else -+ reg &= ~out_data; -+ -+ iowrite32(reg, addr); -+ -+ return 0; -+} -+ - static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -@@ -218,7 +319,10 @@ - - raw_spin_lock_irqsave(&gpio->lock, flags); - -- sgpio_set_value(gc, offset, val); -+ if (gpio->version == 7) -+ sgpio_g7_set_value(gc, offset, val); -+ else -+ sgpio_set_value(gc, offset, val); - - raw_spin_unlock_irqrestore(&gpio->lock, flags); - } -@@ -238,7 +342,10 @@ - * error-out in sgpio_set_value if this isn't an output GPIO */ - - raw_spin_lock_irqsave(&gpio->lock, flags); -- rc = sgpio_set_value(gc, offset, val); -+ if (gpio->version == 7) -+ rc = sgpio_g7_set_value(gc, offset, val); -+ else -+ rc = sgpio_set_value(gc, offset, val); - raw_spin_unlock_irqrestore(&gpio->lock, flags); - - return rc; -@@ -265,6 +372,19 @@ - *bit = GPIO_BIT(*offset); - } - -+static void irqd_to_aspeed_g7_sgpio_data(struct irq_data *d, -+ struct aspeed_sgpio **gpio, -+ int *offset) -+{ -+ struct aspeed_sgpio *internal; -+ -+ *offset = irqd_to_hwirq(d); -+ internal = irq_data_get_irq_chip_data(d); -+ WARN_ON(!internal); -+ -+ *gpio = internal; -+} -+ - static void aspeed_sgpio_irq_ack(struct irq_data *d) - { - const struct aspeed_sgpio_bank *bank; -@@ -285,6 +405,24 @@ - raw_spin_unlock_irqrestore(&gpio->lock, flags); - } - -+static void aspeed_g7_sgpio_irq_ack(struct irq_data *d) -+{ -+ struct aspeed_sgpio *gpio; -+ unsigned long flags; -+ void __iomem *status_addr; -+ int offset; -+ -+ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -+ -+ status_addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ -+ ast_write_bits(status_addr, SGPIO_G7_IRQ_STS, 1); -+ -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+} -+ - static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) - { - const struct aspeed_sgpio_bank *bank; -@@ -320,6 +458,32 @@ - - } - -+static void aspeed_g7_sgpio_irq_set_mask(struct irq_data *d, bool set) -+{ -+ struct aspeed_sgpio *gpio; -+ unsigned long flags; -+ void __iomem *addr; -+ int offset; -+ -+ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -+ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ -+ /* Unmasking the IRQ */ -+ if (set) -+ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); -+ -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ if (set) -+ ast_write_bits(addr, SGPIO_G7_IRQ_EN, 1); -+ else -+ ast_clr_bits(addr, SGPIO_G7_IRQ_EN); -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ /* Masking the IRQ */ -+ if (!set) -+ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); -+} -+ - static void aspeed_sgpio_irq_mask(struct irq_data *d) - { - aspeed_sgpio_irq_set_mask(d, false); -@@ -330,6 +494,16 @@ - aspeed_sgpio_irq_set_mask(d, true); - } - -+static void aspeed_g7_sgpio_irq_mask(struct irq_data *d) -+{ -+ aspeed_g7_sgpio_irq_set_mask(d, false); -+} -+ -+static void aspeed_g7_sgpio_irq_unmask(struct irq_data *d) -+{ -+ aspeed_g7_sgpio_irq_set_mask(d, true); -+} -+ - static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) - { - u32 type0 = 0; -@@ -390,6 +564,53 @@ - return 0; - } - -+static int aspeed_g7_sgpio_set_type(struct irq_data *d, unsigned int type) -+{ -+ u32 type0 = 0; -+ u32 type1 = 0; -+ u32 type2 = 0; -+ irq_flow_handler_t handler; -+ struct aspeed_sgpio *gpio; -+ unsigned long flags; -+ void __iomem *addr; -+ int offset; -+ -+ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -+ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ -+ switch (type & IRQ_TYPE_SENSE_MASK) { -+ case IRQ_TYPE_EDGE_BOTH: -+ type2 = 1; -+ fallthrough; -+ case IRQ_TYPE_EDGE_RISING: -+ type0 = 1; -+ fallthrough; -+ case IRQ_TYPE_EDGE_FALLING: -+ handler = handle_edge_irq; -+ break; -+ case IRQ_TYPE_LEVEL_HIGH: -+ type0 = 1; -+ fallthrough; -+ case IRQ_TYPE_LEVEL_LOW: -+ type1 = 1; -+ handler = handle_level_irq; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ -+ ast_write_bits(addr, SGPIO_G7_IRQ_TYPE2, type2); -+ ast_write_bits(addr, SGPIO_G7_IRQ_TYPE1, type1); -+ ast_write_bits(addr, SGPIO_G7_IRQ_TYPE0, type0); -+ -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ irq_set_handler_locked(d, handler); -+ return 0; -+} -+ - static void aspeed_sgpio_irq_handler(struct irq_desc *desc) - { - struct gpio_chip *gc = irq_desc_get_handler_data(desc); -@@ -412,6 +633,29 @@ - chained_irq_exit(ic, desc); - } - -+static void aspeed_g7_sgpio_irq_handler(struct irq_desc *desc) -+{ -+ struct gpio_chip *gc = irq_desc_get_handler_data(desc); -+ struct irq_chip *ic = irq_desc_get_chip(desc); -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ unsigned int i, p, banks; -+ unsigned long reg; -+ void __iomem *addr; -+ -+ chained_irq_enter(ic, desc); -+ -+ banks = DIV_ROUND_UP(gpio->chip.ngpio >> 1, 32); -+ for (i = 0; i < banks; i++) { -+ addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(i); -+ -+ reg = ioread32(addr); -+ -+ for_each_set_bit(p, ®, 32) -+ generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2); -+ } -+ chained_irq_exit(ic, desc); -+} -+ - static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) - { - const struct aspeed_sgpio_bank *bank; -@@ -423,6 +667,15 @@ - seq_printf(p, dev_name(gpio->dev)); - } - -+static void aspeed_g7_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) -+{ -+ struct aspeed_sgpio *gpio; -+ int offset; -+ -+ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -+ seq_printf(p, dev_name(gpio->dev)); -+} -+ - static const struct irq_chip aspeed_sgpio_irq_chip = { - .irq_ack = aspeed_sgpio_irq_ack, - .irq_mask = aspeed_sgpio_irq_mask, -@@ -433,6 +686,16 @@ - GPIOCHIP_IRQ_RESOURCE_HELPERS, - }; - -+static const struct irq_chip aspeed_g7_sgpio_irq_chip = { -+ .irq_ack = aspeed_g7_sgpio_irq_ack, -+ .irq_mask = aspeed_g7_sgpio_irq_mask, -+ .irq_unmask = aspeed_g7_sgpio_irq_unmask, -+ .irq_set_type = aspeed_g7_sgpio_set_type, -+ .irq_print_chip = aspeed_g7_sgpio_irq_print_chip, -+ .flags = IRQCHIP_IMMUTABLE, -+ GPIOCHIP_IRQ_RESOURCE_HELPERS, -+}; -+ - static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, - struct platform_device *pdev) - { -@@ -446,41 +709,49 @@ - - gpio->irq = rc; - -- /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ -- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -- bank = &aspeed_sgpio_banks[i]; -- /* disable irq enable bits */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); -- /* clear status bits */ -- iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); -- } -+ if (gpio->version != 7) -+ /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ -+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -+ bank = &aspeed_sgpio_banks[i]; -+ /* disable irq enable bits */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); -+ /* clear status bits */ -+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); -+ } - - irq = &gpio->chip.irq; -- gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip); -+ if (gpio->version == 7) -+ gpio_irq_chip_set_chip(irq, &aspeed_g7_sgpio_irq_chip); -+ else -+ gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip); - irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask; - irq->handler = handle_bad_irq; - irq->default_type = IRQ_TYPE_NONE; -- irq->parent_handler = aspeed_sgpio_irq_handler; -+ irq->parent_handler = (gpio->version == 7) ? -+ aspeed_g7_sgpio_irq_handler : -+ aspeed_sgpio_irq_handler; - irq->parent_handler_data = gpio; - irq->parents = &gpio->irq; - irq->num_parents = 1; - -- /* Apply default IRQ settings */ -- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -- bank = &aspeed_sgpio_banks[i]; -- /* set falling or level-low irq */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); -- /* trigger type is edge */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); -- /* single edge trigger */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); -- } -+ if (gpio->version != 7) -+ /* Apply default IRQ settings */ -+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -+ bank = &aspeed_sgpio_banks[i]; -+ /* set falling or level-low irq */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); -+ /* trigger type is edge */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); -+ /* single edge trigger */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); -+ } - - return 0; - } - - static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { - .pin_mask = GENMASK(9, 6), -+ .ctrl_reg = 0x54, - }; - - static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, -@@ -509,38 +780,81 @@ - return 0; - } - -+static int aspeed_g7_sgpio_reset_tolerance(struct gpio_chip *chip, -+ unsigned int offset, bool enable) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(chip); -+ unsigned long flags; -+ void __iomem *reg; -+ -+ reg = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ -+ if (enable) -+ ast_write_bits(reg, SGPIO_G7_RST_TOLERANCE, 1); -+ else -+ ast_clr_bits(reg, SGPIO_G7_RST_TOLERANCE); -+ -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ return 0; -+} -+ - static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, - unsigned long config) - { -+ struct aspeed_sgpio *gpio = gpiochip_get_data(chip); - unsigned long param = pinconf_to_config_param(config); - u32 arg = pinconf_to_config_argument(config); - -- if (param == PIN_CONFIG_PERSIST_STATE) -- return aspeed_sgpio_reset_tolerance(chip, offset, arg); -+ if (param == PIN_CONFIG_PERSIST_STATE) { -+ if (gpio->version == 7) -+ return aspeed_g7_sgpio_reset_tolerance(chip, offset, -+ arg); -+ else -+ return aspeed_sgpio_reset_tolerance(chip, offset, arg); -+ } - - return -ENOTSUPP; - } - - static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { - .pin_mask = GENMASK(10, 6), -+ .ctrl_reg = 0x54, -+}; -+ -+static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = { -+ .pin_mask = GENMASK(11, 6), -+ .ctrl_reg = 0x0, -+ .version = 7, -+}; -+ -+static const struct aspeed_sgpio_pdata ast2700_sgpios_pdata = { -+ .pin_mask = GENMASK(11, 6), -+ .ctrl_reg = 0x0, -+ .version = 7, -+ .slave = 1, - }; ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Stefan Schaeckeler "); ++MODULE_DESCRIPTION("Aspeed BMC SoC EDAC driver"); ++MODULE_VERSION("1.0"); +diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c +--- a/drivers/fsi/fsi-master-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/fsi/fsi-master-aspeed.c 2026-09-09 15:51:44.520241063 +0000 +@@ -3,6 +3,7 @@ + // FSI master driver for AST2600 - static const struct of_device_id aspeed_sgpio_of_table[] = { - { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, }, - { .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, }, - { .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, }, -+ { .compatible = "aspeed,ast2700-sgpiom", .data = &ast2700_sgpiom_pdata, }, -+ { .compatible = "aspeed,ast2700-sgpios", .data = &ast2700_sgpios_pdata, }, - {} - }; - - MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); - --static int __init aspeed_sgpio_probe(struct platform_device *pdev) -+static int aspeed_sgpio_probe(struct platform_device *pdev) - { - u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask; -- const struct aspeed_sgpio_pdata *pdata; - struct aspeed_sgpio *gpio; - unsigned long apb_freq; -- int rc; -+ void __iomem *addr; -+ int rc, i; - - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) -@@ -552,11 +866,12 @@ - - gpio->dev = &pdev->dev; - -- pdata = device_get_match_data(&pdev->dev); -- if (!pdata) -+ gpio->pdata = device_get_match_data(&pdev->dev); -+ if (!gpio->pdata) - return -EINVAL; - -- pin_mask = pdata->pin_mask; -+ pin_mask = gpio->pdata->pin_mask; -+ gpio->version = gpio->pdata->version; - - rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); - if (rc < 0) { -@@ -568,41 +883,53 @@ - return -EINVAL; - } - -- rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); -- if (rc < 0) { -- dev_err(&pdev->dev, "Could not read bus-frequency property\n"); -- return -EINVAL; -+ if (gpio->version == 7 && !gpio->pdata->slave) -+ for (i = 0; i < nr_gpios; i++) { -+ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(i); -+ ast_write_bits(addr, SGPIO_G7_SERIAL_OUT_SEL, -+ SELECT_FROM_CSR); -+ } -+ -+ if (!gpio->pdata->slave) { -+ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); -+ if (rc < 0) { -+ dev_err(&pdev->dev, "Could not read bus-frequency property\n"); -+ return -EINVAL; -+ } -+ -+ gpio->pclk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(gpio->pclk)) { -+ dev_err(&pdev->dev, "devm_clk_get failed\n"); -+ return PTR_ERR(gpio->pclk); -+ } -+ -+ apb_freq = clk_get_rate(gpio->pclk); -+ -+ /* -+ * From the datasheet, -+ * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) -+ * period = 2 * (GPIO254[31:16] + 1) / PCLK -+ * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) -+ * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) -+ * frequency * 2 * (GPIO254[31:16] + 1) = PCLK -+ * GPIO254[31:16] = PCLK / (frequency * 2) - 1 -+ */ -+ if (sgpio_freq == 0) -+ return -EINVAL; -+ -+ sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; -+ -+ if (sgpio_clk_div > (1 << 16) - 1) -+ return -EINVAL; -+ -+ gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; -+ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | -+ gpio_cnt_regval | ASPEED_SGPIO_ENABLE, -+ gpio->base + gpio->pdata->ctrl_reg); -+ } else { -+ iowrite32(ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->ctrl_reg); - } - -- gpio->pclk = devm_clk_get(&pdev->dev, NULL); -- if (IS_ERR(gpio->pclk)) { -- dev_err(&pdev->dev, "devm_clk_get failed\n"); -- return PTR_ERR(gpio->pclk); -- } -- -- apb_freq = clk_get_rate(gpio->pclk); -- -- /* -- * From the datasheet, -- * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) -- * period = 2 * (GPIO254[31:16] + 1) / PCLK -- * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) -- * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) -- * frequency * 2 * (GPIO254[31:16] + 1) = PCLK -- * GPIO254[31:16] = PCLK / (frequency * 2) - 1 -- */ -- if (sgpio_freq == 0) -- return -EINVAL; -- -- sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; -- -- if (sgpio_clk_div > (1 << 16) - 1) -- return -EINVAL; -- -- gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; -- iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | -- ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL); -- - raw_spin_lock_init(&gpio->lock); - - gpio->chip.parent = &pdev->dev; -@@ -629,11 +956,12 @@ - } - - static struct platform_driver aspeed_sgpio_driver = { -+ .probe = aspeed_sgpio_probe, - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = aspeed_sgpio_of_table, - }, - }; - --module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); -+module_platform_driver(aspeed_sgpio_driver); - MODULE_DESCRIPTION("Aspeed Serial GPIO Driver"); -diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c ---- a/drivers/gpio/gpio-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpio/gpio-aspeed.c 2025-12-23 10:16:21.049033926 +0000 -@@ -30,6 +30,27 @@ - #include - #include "gpiolib.h" - -+/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -+#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) -+ -+#define GPIO_G7_IRQ_STS_BASE 0x100 -+#define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4) -+#define GPIO_G7_CTRL_REG_BASE 0x180 -+#define GPIO_G7_CTRL_REG_OFFSET(x) (GPIO_G7_CTRL_REG_BASE + (x) * 0x4) -+#define GPIO_G7_CTRL_OUT_DATA BIT(0) -+#define GPIO_G7_CTRL_DIR BIT(1) -+#define GPIO_G7_CTRL_IRQ_EN BIT(2) -+#define GPIO_G7_CTRL_IRQ_TYPE0 BIT(3) -+#define GPIO_G7_CTRL_IRQ_TYPE1 BIT(4) -+#define GPIO_G7_CTRL_IRQ_TYPE2 BIT(5) -+#define GPIO_G7_CTRL_RST_TOLERANCE BIT(6) -+#define GPIO_G7_CTRL_DEBOUNCE_SEL1 BIT(7) -+#define GPIO_G7_CTRL_DEBOUNCE_SEL2 BIT(8) -+#define GPIO_G7_CTRL_INPUT_MASK BIT(9) -+#define GPIO_G7_CTRL_IRQ_STS BIT(12) -+#define GPIO_G7_CTRL_IN_DATA BIT(13) -+ - struct aspeed_bank_props { - unsigned int bank; - u32 input; -@@ -39,6 +60,10 @@ - struct aspeed_gpio_config { - unsigned int nr_gpios; - const struct aspeed_bank_props *props; -+ const struct aspeed_gpio_llops *llops; -+ const int *debounce_timers_array; -+ int debounce_timers_num; -+ bool require_dcache; - }; - - /* -@@ -77,7 +102,6 @@ - uint16_t debounce_regs; - uint16_t tolerance_regs; - uint16_t cmdsrc_regs; -- const char names[4][3]; - }; - - /* -@@ -92,6 +116,22 @@ - */ - - static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; -+static const int g7_debounce_timers[4] = { 0x00, 0x00, 0x04, 0x08 }; -+ -+/* -+ * The debounce timers array is used to configure the debounce timer settings.Here’s how it works: -+ * Array Value: Indicates the offset for configuring the debounce timer. -+ * Array Index: Corresponds to the debounce setting register. -+ * The debounce timers array follows this pattern for configuring the debounce setting registers: -+ * Array Index 0: No debounce timer is set; -+ * Array Value is irrelevant (don’t care). -+ * Array Index 1: Debounce setting #2 is set to 1, and debounce setting #1 is set to 0. -+ * Array Value: offset for configuring debounce timer 0 (g4: 0x50, g7: 0x00) -+ * Array Index 2: Debounce setting #2 is set to 0, and debounce setting #1 is set to 1. -+ * Array Value: offset for configuring debounce timer 1 (g4: 0x54, g7: 0x04) -+ * Array Index 3: Debounce setting #2 is set to 1, and debounce setting #1 is set to 1. -+ * Array Value: offset for configuring debounce timer 2 (g4: 0x58, g7: 0x8) -+ */ - - static const struct aspeed_gpio_copro_ops *copro_ops; - static void *copro_data; -@@ -104,7 +144,6 @@ - .debounce_regs = 0x0040, - .tolerance_regs = 0x001c, - .cmdsrc_regs = 0x0060, -- .names = { "A", "B", "C", "D" }, - }, - { - .val_regs = 0x0020, -@@ -113,7 +152,6 @@ - .debounce_regs = 0x0048, - .tolerance_regs = 0x003c, - .cmdsrc_regs = 0x0068, -- .names = { "E", "F", "G", "H" }, - }, - { - .val_regs = 0x0070, -@@ -122,7 +160,6 @@ - .debounce_regs = 0x00b0, - .tolerance_regs = 0x00ac, - .cmdsrc_regs = 0x0090, -- .names = { "I", "J", "K", "L" }, - }, - { - .val_regs = 0x0078, -@@ -131,7 +168,6 @@ - .debounce_regs = 0x0100, - .tolerance_regs = 0x00fc, - .cmdsrc_regs = 0x00e0, -- .names = { "M", "N", "O", "P" }, - }, - { - .val_regs = 0x0080, -@@ -140,7 +176,6 @@ - .debounce_regs = 0x0130, - .tolerance_regs = 0x012c, - .cmdsrc_regs = 0x0110, -- .names = { "Q", "R", "S", "T" }, - }, - { - .val_regs = 0x0088, -@@ -149,7 +184,6 @@ - .debounce_regs = 0x0160, - .tolerance_regs = 0x015c, - .cmdsrc_regs = 0x0140, -- .names = { "U", "V", "W", "X" }, - }, - { - .val_regs = 0x01E0, -@@ -158,7 +192,6 @@ - .debounce_regs = 0x0190, - .tolerance_regs = 0x018c, - .cmdsrc_regs = 0x0170, -- .names = { "Y", "Z", "AA", "AB" }, - }, - { - .val_regs = 0x01e8, -@@ -167,7 +200,6 @@ - .debounce_regs = 0x01c0, - .tolerance_regs = 0x01bc, - .cmdsrc_regs = 0x01a0, -- .names = { "AC", "", "", "" }, - }, - }; - -@@ -187,6 +219,19 @@ - reg_cmdsrc1, - }; - -+struct aspeed_gpio_llops { -+ void (*reg_bit_set)(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg, bool val); -+ bool (*reg_bit_get)(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg); -+ int (*reg_bank_get)(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg); -+ void (*privilege_ctrl)(struct aspeed_gpio *gpio, unsigned int offset, int owner); -+ void (*privilege_init)(struct aspeed_gpio *gpio); -+ bool (*copro_request)(struct aspeed_gpio *gpio, unsigned int offset); -+ void (*copro_release)(struct aspeed_gpio *gpio, unsigned int offset); -+}; -+ - #define GPIO_VAL_VALUE 0x00 - #define GPIO_VAL_DIR 0x04 - -@@ -207,9 +252,9 @@ - #define GPIO_CMDSRC_RESERVED 3 - - /* This will be resolved at compile time */ --static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, -- const struct aspeed_gpio_bank *bank, -- const enum aspeed_gpio_reg reg) -+static void __iomem *aspeed_gpio_g4_bank_reg(struct aspeed_gpio *gpio, -+ const struct aspeed_gpio_bank *bank, -+ const enum aspeed_gpio_reg reg) - { - switch (reg) { - case reg_val: -@@ -242,14 +287,43 @@ - BUG(); - } - -+static u32 aspeed_gpio_g7_reg_mask(const enum aspeed_gpio_reg reg) -+{ -+ switch (reg) { -+ case reg_val: -+ return GPIO_G7_CTRL_OUT_DATA; -+ case reg_dir: -+ return GPIO_G7_CTRL_DIR; -+ case reg_irq_enable: -+ return GPIO_G7_CTRL_IRQ_EN; -+ case reg_irq_type0: -+ return GPIO_G7_CTRL_IRQ_TYPE0; -+ case reg_irq_type1: -+ return GPIO_G7_CTRL_IRQ_TYPE1; -+ case reg_irq_type2: -+ return GPIO_G7_CTRL_IRQ_TYPE2; -+ case reg_tolerance: -+ return GPIO_G7_CTRL_RST_TOLERANCE; -+ case reg_debounce_sel1: -+ return GPIO_G7_CTRL_DEBOUNCE_SEL1; -+ case reg_debounce_sel2: -+ return GPIO_G7_CTRL_DEBOUNCE_SEL2; -+ case reg_rdata: -+ return GPIO_G7_CTRL_OUT_DATA; -+ case reg_irq_status: -+ return GPIO_G7_CTRL_IRQ_STS; -+ case reg_cmdsrc0: -+ case reg_cmdsrc1: -+ default: -+ WARN_ON_ONCE(1); -+ return 0; -+ } -+} -+ - #define GPIO_BANK(x) ((x) >> 5) - #define GPIO_OFFSET(x) ((x) & 0x1f) - #define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) - --#define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o)) --#define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1) --#define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0) -- - static const struct aspeed_gpio_bank *to_bank(unsigned int offset) - { - unsigned int bank = GPIO_BANK(offset); -@@ -280,11 +354,11 @@ - static inline bool have_gpio(struct aspeed_gpio *gpio, unsigned int offset) - { - const struct aspeed_bank_props *props = find_bank_props(gpio, offset); -- const struct aspeed_gpio_bank *bank = to_bank(offset); -- unsigned int group = GPIO_OFFSET(offset) / 8; - -- return bank->names[group][0] != '\0' && -- (!props || ((props->input | props->output) & GPIO_BIT(offset))); -+ if (offset >= gpio->chip.ngpio) -+ return false; -+ -+ return (!props || ((props->input | props->output) & GPIO_BIT(offset))); - } - - static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset) -@@ -304,110 +378,49 @@ - return !props || (props->output & GPIO_BIT(offset)); - } - --static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, -- const struct aspeed_gpio_bank *bank, -- int bindex, int cmdsrc) --{ -- void __iomem *c0 = bank_reg(gpio, bank, reg_cmdsrc0); -- void __iomem *c1 = bank_reg(gpio, bank, reg_cmdsrc1); -- u32 bit, reg; -- -- /* -- * Each register controls 4 banks, so take the bottom 2 -- * bits of the bank index, and use them to select the -- * right control bit (0, 8, 16 or 24). -- */ -- bit = BIT((bindex & 3) << 3); -- -- /* Source 1 first to avoid illegal 11 combination */ -- reg = ioread32(c1); -- if (cmdsrc & 2) -- reg |= bit; -- else -- reg &= ~bit; -- iowrite32(reg, c1); -- -- /* Then Source 0 */ -- reg = ioread32(c0); -- if (cmdsrc & 1) -- reg |= bit; -- else -- reg &= ~bit; -- iowrite32(reg, c0); -+static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) -+{ -+ if (gpio->config->llops->privilege_ctrl) -+ gpio->config->llops->privilege_ctrl(gpio, offset, cmdsrc); - } - - static bool aspeed_gpio_copro_request(struct aspeed_gpio *gpio, - unsigned int offset) - { -- const struct aspeed_gpio_bank *bank = to_bank(offset); -+ if (gpio->config->llops->copro_request) -+ return gpio->config->llops->copro_request(gpio, offset); - -- if (!copro_ops || !gpio->cf_copro_bankmap) -- return false; -- if (!gpio->cf_copro_bankmap[offset >> 3]) -- return false; -- if (!copro_ops->request_access) -- return false; -- -- /* Pause the coprocessor */ -- copro_ops->request_access(copro_data); -- -- /* Change command source back to ARM */ -- aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, GPIO_CMDSRC_ARM); -- -- /* Update cache */ -- gpio->dcache[GPIO_BANK(offset)] = ioread32(bank_reg(gpio, bank, reg_rdata)); -- -- return true; -+ return false; - } - - static void aspeed_gpio_copro_release(struct aspeed_gpio *gpio, - unsigned int offset) - { -- const struct aspeed_gpio_bank *bank = to_bank(offset); -- -- if (!copro_ops || !gpio->cf_copro_bankmap) -- return; -- if (!gpio->cf_copro_bankmap[offset >> 3]) -- return; -- if (!copro_ops->release_access) -- return; -- -- /* Change command source back to ColdFire */ -- aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, -- GPIO_CMDSRC_COLDFIRE); -+ if (gpio->config->llops->copro_release) -+ gpio->config->llops->copro_release(gpio, offset); -+} - -- /* Restart the coprocessor */ -- copro_ops->release_access(copro_data); -+static bool aspeed_gpio_support_copro(struct aspeed_gpio *gpio) -+{ -+ return gpio->config->llops->copro_request && gpio->config->llops->copro_release && -+ gpio->config->llops->privilege_ctrl && gpio->config->llops->privilege_init; - } - - static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) - { - struct aspeed_gpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_gpio_bank *bank = to_bank(offset); - -- return !!(ioread32(bank_reg(gpio, bank, reg_val)) & GPIO_BIT(offset)); -+ return gpio->config->llops->reg_bit_get(gpio, offset, reg_val); - } - - static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, - int val) - { - struct aspeed_gpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_gpio_bank *bank = to_bank(offset); -- void __iomem *addr; -- u32 reg; -- -- addr = bank_reg(gpio, bank, reg_val); -- reg = gpio->dcache[GPIO_BANK(offset)]; - -- if (val) -- reg |= GPIO_BIT(offset); -- else -- reg &= ~GPIO_BIT(offset); -- gpio->dcache[GPIO_BANK(offset)] = reg; -- -- iowrite32(reg, addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_val, val); - /* Flush write */ -- ioread32(addr); -+ gpio->config->llops->reg_bit_get(gpio, offset, reg_val); - } - - static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, -@@ -415,7 +428,7 @@ - { - struct aspeed_gpio *gpio = gpiochip_get_data(gc); - unsigned long flags; -- bool copro; -+ bool copro = false; - - raw_spin_lock_irqsave(&gpio->lock, flags); - copro = aspeed_gpio_copro_request(gpio, offset); -@@ -430,22 +443,16 @@ - static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) - { - struct aspeed_gpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_gpio_bank *bank = to_bank(offset); -- void __iomem *addr = bank_reg(gpio, bank, reg_dir); - unsigned long flags; -- bool copro; -- u32 reg; -+ bool copro = false; - - if (!have_input(gpio, offset)) - return -ENOTSUPP; - - raw_spin_lock_irqsave(&gpio->lock, flags); - -- reg = ioread32(addr); -- reg &= ~GPIO_BIT(offset); -- - copro = aspeed_gpio_copro_request(gpio, offset); -- iowrite32(reg, addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 0); - if (copro) - aspeed_gpio_copro_release(gpio, offset); - -@@ -458,23 +465,17 @@ - unsigned int offset, int val) - { - struct aspeed_gpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_gpio_bank *bank = to_bank(offset); -- void __iomem *addr = bank_reg(gpio, bank, reg_dir); - unsigned long flags; -- bool copro; -- u32 reg; -+ bool copro = false; - - if (!have_output(gpio, offset)) - return -ENOTSUPP; - - raw_spin_lock_irqsave(&gpio->lock, flags); - -- reg = ioread32(addr); -- reg |= GPIO_BIT(offset); -- - copro = aspeed_gpio_copro_request(gpio, offset); - __aspeed_gpio_set(gc, offset, val); -- iowrite32(reg, addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 1); - - if (copro) - aspeed_gpio_copro_release(gpio, offset); -@@ -486,7 +487,6 @@ - static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) - { - struct aspeed_gpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_gpio_bank *bank = to_bank(offset); - unsigned long flags; - u32 val; - -@@ -498,7 +498,7 @@ - - raw_spin_lock_irqsave(&gpio->lock, flags); - -- val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset); -+ val = gpio->config->llops->reg_bit_get(gpio, offset, reg_dir); - - raw_spin_unlock_irqrestore(&gpio->lock, flags); - -@@ -507,8 +507,7 @@ - - static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, - struct aspeed_gpio **gpio, -- const struct aspeed_gpio_bank **bank, -- u32 *bit, int *offset) -+ int *offset) - { - struct aspeed_gpio *internal; - -@@ -521,32 +520,25 @@ - return -ENOTSUPP; - - *gpio = internal; -- *bank = to_bank(*offset); -- *bit = GPIO_BIT(*offset); - - return 0; - } - - static void aspeed_gpio_irq_ack(struct irq_data *d) - { -- const struct aspeed_gpio_bank *bank; - struct aspeed_gpio *gpio; - unsigned long flags; -- void __iomem *status_addr; - int rc, offset; -- bool copro; -- u32 bit; -+ bool copro = false; - -- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); -+ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); - if (rc) - return; - -- status_addr = bank_reg(gpio, bank, reg_irq_status); -- - raw_spin_lock_irqsave(&gpio->lock, flags); - copro = aspeed_gpio_copro_request(gpio, offset); - -- iowrite32(bit, status_addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); - - if (copro) - aspeed_gpio_copro_release(gpio, offset); -@@ -555,20 +547,15 @@ - - static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) - { -- const struct aspeed_gpio_bank *bank; - struct aspeed_gpio *gpio; - unsigned long flags; -- u32 reg, bit; -- void __iomem *addr; - int rc, offset; -- bool copro; -+ bool copro = false; - -- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); -+ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); - if (rc) - return; - -- addr = bank_reg(gpio, bank, reg_irq_enable); -- - /* Unmasking the IRQ */ - if (set) - gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); -@@ -576,12 +563,7 @@ - raw_spin_lock_irqsave(&gpio->lock, flags); - copro = aspeed_gpio_copro_request(gpio, offset); - -- reg = ioread32(addr); -- if (set) -- reg |= bit; -- else -- reg &= ~bit; -- iowrite32(reg, addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_enable, set); - - if (copro) - aspeed_gpio_copro_release(gpio, offset); -@@ -607,34 +589,31 @@ - u32 type0 = 0; - u32 type1 = 0; - u32 type2 = 0; -- u32 bit, reg; -- const struct aspeed_gpio_bank *bank; - irq_flow_handler_t handler; - struct aspeed_gpio *gpio; - unsigned long flags; -- void __iomem *addr; - int rc, offset; -- bool copro; -+ bool copro = false; - -- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); -+ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); - if (rc) - return -EINVAL; - - switch (type & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_EDGE_BOTH: -- type2 |= bit; -+ type2 = 1; - fallthrough; - case IRQ_TYPE_EDGE_RISING: -- type0 |= bit; -+ type0 = 1; - fallthrough; - case IRQ_TYPE_EDGE_FALLING: - handler = handle_edge_irq; - break; - case IRQ_TYPE_LEVEL_HIGH: -- type0 |= bit; -+ type0 = 1; - fallthrough; - case IRQ_TYPE_LEVEL_LOW: -- type1 |= bit; -+ type1 = 1; - handler = handle_level_irq; - break; - default: -@@ -644,20 +623,9 @@ - raw_spin_lock_irqsave(&gpio->lock, flags); - copro = aspeed_gpio_copro_request(gpio, offset); - -- addr = bank_reg(gpio, bank, reg_irq_type0); -- reg = ioread32(addr); -- reg = (reg & ~bit) | type0; -- iowrite32(reg, addr); -- -- addr = bank_reg(gpio, bank, reg_irq_type1); -- reg = ioread32(addr); -- reg = (reg & ~bit) | type1; -- iowrite32(reg, addr); -- -- addr = bank_reg(gpio, bank, reg_irq_type2); -- reg = ioread32(addr); -- reg = (reg & ~bit) | type2; -- iowrite32(reg, addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); - - if (copro) - aspeed_gpio_copro_release(gpio, offset); -@@ -672,7 +640,6 @@ - { - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct irq_chip *ic = irq_desc_get_chip(desc); -- struct aspeed_gpio *data = gpiochip_get_data(gc); - unsigned int i, p, banks; - unsigned long reg; - struct aspeed_gpio *gpio = gpiochip_get_data(gc); -@@ -681,9 +648,7 @@ - - banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); - for (i = 0; i < banks; i++) { -- const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; -- -- reg = ioread32(bank_reg(data, bank, reg_irq_status)); -+ reg = gpio->config->llops->reg_bank_get(gpio, i * 32, reg_irq_status); - - for_each_set_bit(p, ®, 32) - generic_handle_domain_irq(gc->irq.domain, i * 32 + p); -@@ -722,23 +687,12 @@ - { - struct aspeed_gpio *gpio = gpiochip_get_data(chip); - unsigned long flags; -- void __iomem *treg; -- bool copro; -- u32 val; -- -- treg = bank_reg(gpio, to_bank(offset), reg_tolerance); -+ bool copro = false; - - raw_spin_lock_irqsave(&gpio->lock, flags); - copro = aspeed_gpio_copro_request(gpio, offset); - -- val = readl(treg); -- -- if (enable) -- val |= GPIO_BIT(offset); -- else -- val &= ~GPIO_BIT(offset); -- -- writel(val, treg); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); - - if (copro) - aspeed_gpio_copro_release(gpio, offset); -@@ -832,21 +786,11 @@ - static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, - unsigned int timer) - { -- const struct aspeed_gpio_bank *bank = to_bank(offset); -- const u32 mask = GPIO_BIT(offset); -- void __iomem *addr; -- u32 val; -- - /* Note: Debounce timer isn't under control of the command - * source registers, so no need to sync with the coprocessor - */ -- addr = bank_reg(gpio, bank, reg_debounce_sel1); -- val = ioread32(addr); -- iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); -- -- addr = bank_reg(gpio, bank, reg_debounce_sel2); -- val = ioread32(addr); -- iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_debounce_sel1, !!(timer & BIT(1))); -+ gpio->config->llops->reg_bit_set(gpio, offset, reg_debounce_sel2, !!(timer & BIT(0))); - } - - static int enable_debounce(struct gpio_chip *chip, unsigned int offset, -@@ -877,15 +821,15 @@ - } - - /* Try to find a timer already configured for the debounce period */ -- for (i = 1; i < ARRAY_SIZE(debounce_timers); i++) { -+ for (i = 1; i < gpio->config->debounce_timers_num; i++) { - u32 cycles; - -- cycles = ioread32(gpio->base + debounce_timers[i]); -+ cycles = ioread32(gpio->base + gpio->config->debounce_timers_array[i]); - if (requested_cycles == cycles) - break; - } - -- if (i == ARRAY_SIZE(debounce_timers)) { -+ if (i == gpio->config->debounce_timers_num) { - int j; - - /* -@@ -899,8 +843,8 @@ + #include ++#include + #include + #include + #include +@@ -24,9 +25,14 @@ + struct device *dev; + void __iomem *base; + struct clk *clk; ++ struct reset_control *rst; + struct gpio_desc *cfam_reset_gpio; + }; - if (j == ARRAY_SIZE(gpio->timer_users)) { - dev_warn(chip->parent, -- "Debounce timers exhausted, cannot debounce for period %luus\n", -- usecs); -+ "Debounce timers exhausted, cannot debounce for period %luus\n", -+ usecs); ++struct aspeed_fsi_match_data { ++ bool sup_ahb_access; ++}; ++ + #define to_fsi_master_aspeed(m) \ + container_of(m, struct fsi_master_aspeed, master) - rc = -EPERM; +@@ -60,6 +66,8 @@ + #define OPB1_READ_ORDER2 0x60 -@@ -916,7 +860,7 @@ + #define OPB_RETRY_COUNTER 0x64 ++#define OPB_ACCESS_CTRL_REG BIT(18) ++#define OPB_ACCESS_CPU_BRIDGE BIT(19) - i = j; + /* OPBn_STATUS */ + #define STATUS_HALFWORD_ACK BIT(0) +@@ -539,6 +547,7 @@ + struct fsi_master_aspeed *aspeed; + int rc, links, reg; + __be32 raw; ++ const struct aspeed_fsi_match_data *match_data; -- iowrite32(requested_cycles, gpio->base + debounce_timers[i]); -+ iowrite32(requested_cycles, gpio->base + gpio->config->debounce_timers_array[i]); + rc = tacoma_cabled_fsi_fixup(&pdev->dev); + if (rc) { +@@ -558,16 +567,22 @@ + goto err_free_aspeed; } - if (WARN(i == 0, "Cannot register index of disabled timer\n")) { -@@ -1019,6 +963,9 @@ - const struct aspeed_gpio_bank *bank = to_bank(offset); - unsigned long flags; - -+ if (!aspeed_gpio_support_copro(gpio)) -+ return -EOPNOTSUPP; ++ aspeed->rst = devm_reset_control_get_shared(&pdev->dev, NULL); ++ if (IS_ERR(aspeed->rst)) ++ dev_warn(aspeed->dev, "couldn't get reset\n"); ++ else ++ reset_control_deassert(aspeed->rst); + - if (!gpio->cf_copro_bankmap) - gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL); - if (!gpio->cf_copro_bankmap) -@@ -1038,7 +985,7 @@ - - /* Switch command source */ - if (gpio->cf_copro_bankmap[bindex] == 1) -- aspeed_gpio_change_cmd_source(gpio, bank, bindex, -+ aspeed_gpio_change_cmd_source(gpio, offset, - GPIO_CMDSRC_COLDFIRE); - - if (vreg_offset) -@@ -1062,9 +1009,11 @@ - struct gpio_chip *chip = gpiod_to_chip(desc); - struct aspeed_gpio *gpio = gpiochip_get_data(chip); - int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); -- const struct aspeed_gpio_bank *bank = to_bank(offset); - unsigned long flags; + aspeed->clk = devm_clk_get(aspeed->dev, NULL); + if (IS_ERR(aspeed->clk)) { + dev_err(aspeed->dev, "couldn't get clock\n"); + rc = PTR_ERR(aspeed->clk); +- goto err_free_aspeed; ++ goto err_reset; + } + rc = clk_prepare_enable(aspeed->clk); + if (rc) { + dev_err(aspeed->dev, "couldn't enable clock\n"); +- goto err_free_aspeed; ++ goto err_reset; + } -+ if (!aspeed_gpio_support_copro(gpio)) -+ return -EOPNOTSUPP; -+ - if (!gpio->cf_copro_bankmap) - return -ENXIO; + rc = setup_cfam_reset(aspeed); +@@ -580,7 +595,12 @@ + aspeed->base + OPB_IRQ_MASK); -@@ -1083,7 +1032,7 @@ + /* TODO: determine an appropriate value */ +- writel(0x10, aspeed->base + OPB_RETRY_COUNTER); ++ match_data = of_device_get_match_data(&pdev->dev); ++ if (match_data->sup_ahb_access) ++ writel(0x10 | OPB_ACCESS_CTRL_REG | OPB_ACCESS_CPU_BRIDGE, ++ aspeed->base + OPB_RETRY_COUNTER); ++ else ++ writel(0x10, aspeed->base + OPB_RETRY_COUNTER); - /* Switch command source */ - if (gpio->cf_copro_bankmap[bindex] == 0) -- aspeed_gpio_change_cmd_source(gpio, bank, bindex, -+ aspeed_gpio_change_cmd_source(gpio, offset, - GPIO_CMDSRC_ARM); - bail: - raw_spin_unlock_irqrestore(&gpio->lock, flags); -@@ -1093,12 +1042,10 @@ + writel(ctrl_base, aspeed->base + OPB_CTRL_BASE); + writel(fsi_base, aspeed->base + OPB_FSI_BASE); +@@ -641,6 +661,9 @@ - static void aspeed_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) - { -- const struct aspeed_gpio_bank *bank; - struct aspeed_gpio *gpio; -- u32 bit; - int rc, offset; + err_release: + clk_disable_unprepare(aspeed->clk); ++err_reset: ++ if (!IS_ERR(aspeed->rst)) ++ reset_control_assert(aspeed->rst); + err_free_aspeed: + kfree(aspeed); + return rc; +@@ -652,10 +675,21 @@ -- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); -+ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); - if (rc) - return; + fsi_master_unregister(&aspeed->master); + clk_disable_unprepare(aspeed->clk); ++ if (!IS_ERR(aspeed->rst)) ++ reset_control_assert(aspeed->rst); + } -@@ -1115,6 +1062,173 @@ - GPIOCHIP_IRQ_RESOURCE_HELPERS, ++static const struct aspeed_fsi_match_data ast2600_match_data = { ++ .sup_ahb_access = 0, ++}; ++ ++static const struct aspeed_fsi_match_data ast2700_match_data = { ++ .sup_ahb_access = 1, ++}; ++ + static const struct of_device_id fsi_master_aspeed_match[] = { +- { .compatible = "aspeed,ast2600-fsi-master" }, ++ { .compatible = "aspeed,ast2600-fsi-master", .data = &ast2600_match_data }, ++ { .compatible = "aspeed,ast2700-fsi-master", .data = &ast2700_match_data }, + { }, }; - -+static void aspeed_g4_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg, bool val) + MODULE_DEVICE_TABLE(of, fsi_master_aspeed_match); +diff --git a/drivers/gpio/gpio-aspeed-ltpi.c b/drivers/gpio/gpio-aspeed-ltpi.c +--- a/drivers/gpio/gpio-aspeed-ltpi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/gpio/gpio-aspeed-ltpi.c 2026-09-09 15:51:44.642239220 +0000 +@@ -0,0 +1,469 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2024 ASPEED ++ * ++ * Author: Billy Tsai ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define LTPI_GPIO_IRQ_STS_BASE 0x200 ++#define LTPI_GPIO_IRQ_STS_OFFSET(x) (LTPI_GPIO_IRQ_STS_BASE + (x) * 0x4) ++#define LTPI_GPIO_CTRL_REG_BASE 0x0 ++#define LTPI_GPIO_CTRL_REG_OFFSET(x) (LTPI_GPIO_CTRL_REG_BASE + (x) * 0x4) ++#define LTPI_GPIO_OUT_DATA BIT(0) ++#define LTPI_GPIO_IRQ_EN BIT(2) ++#define LTPI_GPIO_IRQ_TYPE0 BIT(3) ++#define LTPI_GPIO_IRQ_TYPE1 BIT(4) ++#define LTPI_GPIO_IRQ_TYPE2 BIT(5) ++#define LTPI_GPIO_RST_TOLERANCE BIT(6) ++#define LTPI_GPIO_IRQ_STS BIT(12) ++#define LTPI_GPIO_IN_DATA BIT(13) ++ ++static inline u32 field_get(u32 _mask, u32 _val) +{ -+ const struct aspeed_gpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); -+ u32 temp; ++ return (((_val) & (_mask)) >> (ffs(_mask) - 1)); ++} + -+ if (reg == reg_val) -+ temp = gpio->dcache[GPIO_BANK(offset)]; -+ else -+ temp = ioread32(addr); ++static inline u32 field_prep(u32 _mask, u32 _val) ++{ ++ return (((_val) << (ffs(_mask) - 1)) & (_mask)); ++} ++ ++static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) ++{ ++ iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); ++} ++ ++static inline void ast_clr_bits(void __iomem *addr, u32 mask) ++{ ++ iowrite32((ioread32(addr) & ~(mask)), addr); ++} ++ ++struct aspeed_ltpi_gpio { ++ struct gpio_chip chip; ++ struct device *dev; ++ raw_spinlock_t lock; ++ void __iomem *base; ++ int irq; ++}; ++ ++static int aspeed_ltpi_gpio_init_valid_mask(struct gpio_chip *gc, ++ unsigned long *valid_mask, ++ unsigned int ngpios) ++{ ++ bitmap_set(valid_mask, 0, ngpios); ++ return 0; ++} ++ ++static void aspeed_ltpi_gpio_irq_init_valid_mask(struct gpio_chip *gc, ++ unsigned long *valid_mask, ++ unsigned int ngpios) ++{ ++ unsigned int i; ++ ++ /* input GPIOs are even bits */ ++ for (i = 0; i < ngpios; i++) { ++ if (i % 2) ++ clear_bit(i, valid_mask); ++ } ++} ++ ++static int aspeed_ltpi_gpio_irq_init_hw(struct gpio_chip *gc) ++{ ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); ++ void __iomem *addr; ++ unsigned long flags; ++ int i; ++ ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ++ for (i = 0; i < (gc->ngpio >> 1); i++) { ++ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(i); ++ ast_clr_bits(addr, LTPI_GPIO_IRQ_EN | LTPI_GPIO_IRQ_TYPE0 | ++ LTPI_GPIO_IRQ_TYPE1 | ++ LTPI_GPIO_IRQ_TYPE2); ++ ast_write_bits(addr, LTPI_GPIO_IRQ_STS, 1); ++ } ++ ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return 0; ++} ++ ++static bool aspeed_ltpi_gpio_is_input(unsigned int offset) ++{ ++ return !(offset % 2); ++} ++ ++static int aspeed_ltpi_gpio_get(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); ++ void __iomem const *addr = ++ gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ unsigned long flags; ++ u32 mask; ++ int rc = 0; ++ ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ++ mask = aspeed_ltpi_gpio_is_input(offset) ? LTPI_GPIO_IN_DATA : ++ LTPI_GPIO_OUT_DATA; ++ rc = !!(field_get(mask, ioread32(addr))); ++ ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return rc; ++} ++ ++static int ltpi_gpio_set_value(struct gpio_chip *gc, unsigned int offset, ++ int val) ++{ ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); ++ void __iomem *addr = ++ gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ u32 reg = 0; ++ ++ if (aspeed_ltpi_gpio_is_input(offset)) ++ return -EINVAL; ++ ++ reg = ioread32(addr); + + if (val) -+ temp |= GPIO_BIT(offset); ++ reg |= LTPI_GPIO_OUT_DATA; + else -+ temp &= ~GPIO_BIT(offset); ++ reg &= ~LTPI_GPIO_OUT_DATA; + -+ if (reg == reg_val) -+ gpio->dcache[GPIO_BANK(offset)] = temp; -+ iowrite32(temp, addr); ++ iowrite32(reg, addr); ++ ++ return 0; +} + -+static bool aspeed_g4_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) ++static void aspeed_ltpi_gpio_set(struct gpio_chip *gc, unsigned int offset, ++ int val) +{ -+ const struct aspeed_gpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); ++ unsigned long flags; + -+ return !!(ioread32(addr) & GPIO_BIT(offset)); ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ltpi_gpio_set_value(gc, offset, val); ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); +} + -+static int aspeed_g4_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) ++static int aspeed_ltpi_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ -+ const struct aspeed_gpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); ++ return aspeed_ltpi_gpio_is_input(offset) ? 0 : -EINVAL; ++} + -+ if (reg == reg_rdata || reg == reg_irq_status) -+ return ioread32(addr); ++static int aspeed_ltpi_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, ++ int val) ++{ ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); ++ unsigned long flags; ++ int rc; ++ ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ rc = ltpi_gpio_set_value(gc, offset, val); ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return rc; ++} ++ ++static int aspeed_ltpi_gpio_get_direction(struct gpio_chip *gc, ++ unsigned int offset) ++{ ++ return !!aspeed_ltpi_gpio_is_input(offset); ++} ++ ++static void irqd_to_aspeed_ltpi_gpio_data(struct irq_data *d, ++ struct aspeed_ltpi_gpio **gpio, ++ int *offset) ++{ ++ struct aspeed_ltpi_gpio *internal; ++ ++ *offset = irqd_to_hwirq(d); ++ internal = irq_data_get_irq_chip_data(d); ++ WARN_ON(!internal); ++ ++ *gpio = internal; ++} ++ ++static void aspeed_ltpi_gpio_irq_ack(struct irq_data *d) ++{ ++ struct aspeed_ltpi_gpio *gpio; ++ unsigned long flags; ++ void __iomem *status_addr; ++ int offset; ++ ++ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ ++ status_addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ++ ast_write_bits(status_addr, LTPI_GPIO_IRQ_STS, 1); ++ ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static void aspeed_ltpi_gpio_irq_set_mask(struct irq_data *d, bool set) ++{ ++ struct aspeed_ltpi_gpio *gpio; ++ unsigned long flags; ++ void __iomem *addr; ++ int offset; ++ ++ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ ++ /* Unmasking the IRQ */ ++ if (set) ++ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); ++ ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ if (set) ++ ast_write_bits(addr, LTPI_GPIO_IRQ_EN, 1); + else -+ return -EOPNOTSUPP; ++ ast_clr_bits(addr, LTPI_GPIO_IRQ_EN); ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ /* Masking the IRQ */ ++ if (!set) ++ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); +} + -+static void aspeed_g4_privilege_ctrl(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) ++static void aspeed_ltpi_gpio_irq_mask(struct irq_data *d) +{ -+ /* -+ * The command source register is only valid in bits 0, 8, 16, and 24, so we use -+ * (offset & ~(0x7)) to ensure that reg_bits_set always targets a valid bit. -+ */ -+ /* Source 1 first to avoid illegal 11 combination */ -+ aspeed_g4_reg_bit_set(gpio, offset & ~(0x7), reg_cmdsrc1, !!(cmdsrc & BIT(1))); -+ /* Then Source 0 */ -+ aspeed_g4_reg_bit_set(gpio, offset & ~(0x7), reg_cmdsrc0, !!(cmdsrc & BIT(0))); ++ aspeed_ltpi_gpio_irq_set_mask(d, false); +} + -+static void aspeed_g4_privilege_init(struct aspeed_gpio *gpio) ++static void aspeed_ltpi_gpio_irq_unmask(struct irq_data *d) ++{ ++ aspeed_ltpi_gpio_irq_set_mask(d, true); ++} ++ ++static int aspeed_ltpi_gpio_set_type(struct irq_data *d, unsigned int type) ++{ ++ u32 type0 = 0; ++ u32 type1 = 0; ++ u32 type2 = 0; ++ irq_flow_handler_t handler; ++ struct aspeed_ltpi_gpio *gpio; ++ unsigned long flags; ++ void __iomem *addr; ++ int offset; ++ ++ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ ++ switch (type & IRQ_TYPE_SENSE_MASK) { ++ case IRQ_TYPE_EDGE_BOTH: ++ type2 = 1; ++ fallthrough; ++ case IRQ_TYPE_EDGE_RISING: ++ type0 = 1; ++ fallthrough; ++ case IRQ_TYPE_EDGE_FALLING: ++ handler = handle_edge_irq; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ type0 = 1; ++ fallthrough; ++ case IRQ_TYPE_LEVEL_LOW: ++ type1 = 1; ++ handler = handle_level_irq; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ++ ast_write_bits(addr, LTPI_GPIO_IRQ_TYPE2, type2); ++ ast_write_bits(addr, LTPI_GPIO_IRQ_TYPE1, type1); ++ ast_write_bits(addr, LTPI_GPIO_IRQ_TYPE0, type0); ++ ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ irq_set_handler_locked(d, handler); ++ return 0; ++} ++ ++static void aspeed_ltpi_gpio_irq_handler(struct irq_desc *desc) ++{ ++ struct gpio_chip *gc = irq_desc_get_handler_data(desc); ++ struct irq_chip *ic = irq_desc_get_chip(desc); ++ struct aspeed_ltpi_gpio const *gpio = gpiochip_get_data(gc); ++ unsigned int i, p, banks; ++ unsigned long reg; ++ void __iomem const *addr; ++ ++ chained_irq_enter(ic, desc); ++ ++ banks = DIV_ROUND_UP(gpio->chip.ngpio >> 1, 32); ++ for (i = 0; i < banks; i++) { ++ addr = gpio->base + LTPI_GPIO_IRQ_STS_OFFSET(i); ++ ++ reg = ioread32(addr); ++ ++ for_each_set_bit(p, ®, 32) ++ generic_handle_domain_irq(gc->irq.domain, ++ (i * 32 + p) * 2); ++ } ++ chained_irq_exit(ic, desc); ++} ++ ++static void aspeed_ltpi_gpio_irq_print_chip(struct irq_data *d, ++ struct seq_file *p) ++{ ++ struct aspeed_ltpi_gpio *gpio; ++ int offset; ++ ++ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ seq_printf(p, dev_name(gpio->dev)); ++} ++ ++static const struct irq_chip aspeed_ltpi_gpio_irq_chip = { ++ .irq_ack = aspeed_ltpi_gpio_irq_ack, ++ .irq_mask = aspeed_ltpi_gpio_irq_mask, ++ .irq_unmask = aspeed_ltpi_gpio_irq_unmask, ++ .irq_set_type = aspeed_ltpi_gpio_set_type, ++ .irq_print_chip = aspeed_ltpi_gpio_irq_print_chip, ++ .flags = IRQCHIP_IMMUTABLE, ++ GPIOCHIP_IRQ_RESOURCE_HELPERS, ++}; ++ ++static int aspeed_ltpi_gpio_setup_irqs(struct aspeed_ltpi_gpio *gpio, ++ struct platform_device *pdev) +{ -+ u32 i; ++ int rc; ++ struct gpio_irq_chip *irq; + -+ /* Switch all command sources to the ARM by default */ -+ for (i = 0; i < DIV_ROUND_UP(gpio->chip.ngpio, 32); i++) { -+ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 0, GPIO_CMDSRC_ARM); -+ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 8, GPIO_CMDSRC_ARM); -+ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 16, GPIO_CMDSRC_ARM); -+ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 24, GPIO_CMDSRC_ARM); -+ } ++ rc = platform_get_irq(pdev, 0); ++ if (rc < 0) ++ return rc; ++ ++ gpio->irq = rc; ++ ++ irq = &gpio->chip.irq; ++ gpio_irq_chip_set_chip(irq, &aspeed_ltpi_gpio_irq_chip); ++ irq->init_valid_mask = aspeed_ltpi_gpio_irq_init_valid_mask; ++ irq->handler = handle_bad_irq; ++ irq->init_hw = aspeed_ltpi_gpio_irq_init_hw; ++ irq->default_type = IRQ_TYPE_NONE; ++ irq->parent_handler = aspeed_ltpi_gpio_irq_handler; ++ irq->parent_handler_data = gpio; ++ irq->parents = &gpio->irq; ++ irq->num_parents = 1; ++ ++ return 0; +} + -+static bool aspeed_g4_copro_request(struct aspeed_gpio *gpio, unsigned int offset) ++static int aspeed_ltpi_gpio_reset_tolerance(struct gpio_chip *chip, ++ unsigned int offset, bool enable) +{ -+ if (!copro_ops || !gpio->cf_copro_bankmap) -+ return false; -+ if (!gpio->cf_copro_bankmap[offset >> 3]) -+ return false; -+ if (!copro_ops->request_access) -+ return false; ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(chip); ++ unsigned long flags; ++ void __iomem *reg; + -+ /* Pause the coprocessor */ -+ copro_ops->request_access(copro_data); ++ reg = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); + -+ /* Change command source back to ARM */ -+ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_ARM); ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+ /* Update cache */ -+ gpio->dcache[GPIO_BANK(offset)] = aspeed_g4_reg_bank_get(gpio, offset, reg_rdata); ++ if (enable) ++ ast_write_bits(reg, LTPI_GPIO_RST_TOLERANCE, 1); ++ else ++ ast_clr_bits(reg, LTPI_GPIO_RST_TOLERANCE); + -+ return true; ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return 0; +} + -+static void aspeed_g4_copro_release(struct aspeed_gpio *gpio, unsigned int offset) ++static int aspeed_ltpi_gpio_set_config(struct gpio_chip *chip, ++ unsigned int offset, ++ unsigned long config) +{ -+ if (!copro_ops || !gpio->cf_copro_bankmap) -+ return; -+ if (!gpio->cf_copro_bankmap[offset >> 3]) -+ return; -+ if (!copro_ops->release_access) -+ return; ++ unsigned long param = pinconf_to_config_param(config); ++ u32 arg = pinconf_to_config_argument(config); + -+ /* Change command source back to ColdFire */ -+ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_COLDFIRE); ++ if (param == PIN_CONFIG_PERSIST_STATE) ++ return aspeed_ltpi_gpio_reset_tolerance(chip, offset, arg); + -+ /* Restart the coprocessor */ -+ copro_ops->release_access(copro_data); ++ return -EOPNOTSUPP; +} + -+static const struct aspeed_gpio_llops aspeed_g4_llops = { -+ .reg_bit_set = aspeed_g4_reg_bit_set, -+ .reg_bit_get = aspeed_g4_reg_bit_get, -+ .reg_bank_get = aspeed_g4_reg_bank_get, -+ .privilege_ctrl = aspeed_g4_privilege_ctrl, -+ .privilege_init = aspeed_g4_privilege_init, -+ .copro_request = aspeed_g4_copro_request, -+ .copro_release = aspeed_g4_copro_release, ++static const struct of_device_id aspeed_ltpi_gpio_of_table[] = { ++ { .compatible = "aspeed,ast2700-ltpi-gpio" }, ++ {} +}; + -+static void aspeed_g7_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg, bool val) ++MODULE_DEVICE_TABLE(of, aspeed_ltpi_gpio_of_table); ++ ++static int __init aspeed_ltpi_gpio_probe(struct platform_device *pdev) +{ -+ u32 mask = aspeed_gpio_g7_reg_mask(reg); -+ void __iomem *addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); -+ u32 write_val; ++ u32 nr_gpios; ++ struct aspeed_ltpi_gpio *gpio; ++ int rc; + -+ if (mask) { -+ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); -+ iowrite32(write_val, addr); ++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); ++ if (!gpio) ++ return -ENOMEM; ++ ++ gpio->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(gpio->base)) ++ return PTR_ERR(gpio->base); ++ ++ gpio->dev = &pdev->dev; ++ ++ rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "Could not read ngpios property\n"); ++ return -EINVAL; + } -+} + -+static bool aspeed_g7_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) -+{ -+ u32 mask = aspeed_gpio_g7_reg_mask(reg); -+ void __iomem *addr; ++ raw_spin_lock_init(&gpio->lock); + -+ addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); -+ if (reg == reg_val) -+ mask = GPIO_G7_CTRL_IN_DATA; ++ gpio->chip.parent = &pdev->dev; ++ gpio->chip.ngpio = nr_gpios * 2; ++ gpio->chip.init_valid_mask = aspeed_ltpi_gpio_init_valid_mask; ++ gpio->chip.direction_input = aspeed_ltpi_gpio_dir_in; ++ gpio->chip.direction_output = aspeed_ltpi_gpio_dir_out; ++ gpio->chip.get_direction = aspeed_ltpi_gpio_get_direction; ++ gpio->chip.request = NULL; ++ gpio->chip.free = NULL; ++ gpio->chip.get = aspeed_ltpi_gpio_get; ++ gpio->chip.set = aspeed_ltpi_gpio_set; ++ gpio->chip.set_config = aspeed_ltpi_gpio_set_config; ++ gpio->chip.label = dev_name(&pdev->dev); ++ gpio->chip.base = -1; + -+ if (mask) -+ return field_get(mask, ioread32(addr)); -+ else -+ return 0; -+} ++ aspeed_ltpi_gpio_setup_irqs(gpio, pdev); + -+static int aspeed_g7_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) -+{ -+ void __iomem *addr; ++ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); ++ if (rc < 0) ++ return rc; + -+ if (reg == reg_irq_status) { -+ addr = gpio->base + GPIO_G7_IRQ_STS_OFFSET(offset >> 5); -+ return ioread32(addr); -+ } else { -+ return -EOPNOTSUPP; -+ } ++ return 0; +} + -+static const struct aspeed_gpio_llops aspeed_g7_llops = { -+ .reg_bit_set = aspeed_g7_reg_bit_set, -+ .reg_bit_get = aspeed_g7_reg_bit_get, -+ .reg_bank_get = aspeed_g7_reg_bank_get, -+ .privilege_ctrl = NULL, -+ .privilege_init = NULL, -+ .copro_request = NULL, -+ .copro_release = NULL, ++static struct platform_driver aspeed_ltpi_gpio_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_ltpi_gpio_of_table, ++ }, +}; + - /* - * Any banks not specified in a struct aspeed_bank_props array are assumed to - * have the properties: -@@ -1131,7 +1245,14 @@ - - static const struct aspeed_gpio_config ast2400_config = - /* 220 for simplicity, really 216 with two 4-GPIO holes, four at end */ -- { .nr_gpios = 220, .props = ast2400_bank_props, }; -+ { -+ .nr_gpios = 220, -+ .props = ast2400_bank_props, -+ .llops = &aspeed_g4_llops, -+ .debounce_timers_array = debounce_timers, -+ .debounce_timers_num = ARRAY_SIZE(debounce_timers), -+ .require_dcache = true, -+ }; - - static const struct aspeed_bank_props ast2500_bank_props[] = { - /* input output */ -@@ -1143,7 +1264,14 @@ ++module_platform_driver_probe(aspeed_ltpi_gpio_driver, aspeed_ltpi_gpio_probe); ++MODULE_DESCRIPTION("Aspeed LTPI GPIO Driver"); +diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c +--- a/drivers/gpio/gpio-aspeed-sgpio.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpio/gpio-aspeed-sgpio.c 2026-09-09 15:51:44.637239295 +0000 +@@ -6,6 +6,7 @@ + */ - static const struct aspeed_gpio_config ast2500_config = - /* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */ -- { .nr_gpios = 232, .props = ast2500_bank_props, }; -+ { -+ .nr_gpios = 232, -+ .props = ast2500_bank_props, -+ .llops = &aspeed_g4_llops, -+ .debounce_timers_array = debounce_timers, -+ .debounce_timers_num = ARRAY_SIZE(debounce_timers), -+ .require_dcache = true, -+ }; + #include ++#include + #include + #include + #include +@@ -18,14 +19,50 @@ + #include + #include - static const struct aspeed_bank_props ast2600_bank_props[] = { - /* input output */ -@@ -1159,17 +1287,48 @@ - * We expect ngpio being set in the device tree and this is a fallback - * option. - */ -- { .nr_gpios = 208, .props = ast2600_bank_props, }; -+ { -+ .nr_gpios = 208, -+ .props = ast2600_bank_props, -+ .llops = &aspeed_g4_llops, -+ .debounce_timers_array = debounce_timers, -+ .debounce_timers_num = ARRAY_SIZE(debounce_timers), -+ .require_dcache = true, -+ }; +-#define ASPEED_SGPIO_CTRL 0x54 ++/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ ++#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) ++#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + -+static const struct aspeed_bank_props ast2700_bank_props[] = { -+ /* input output */ -+ { 1, 0x0fffffff, 0x0fffffff }, /* E/F/G/H, 4-GPIO hole */ -+ { 6, 0x00ffffff, 0x00ff0000 }, /* Y/Z/AA */ -+ {}, -+}; ++#define SGPIO_G7_IRQ_STS_BASE 0x40 ++#define SGPIO_G7_IRQ_STS_OFFSET(x) (SGPIO_G7_IRQ_STS_BASE + (x) * 0x4) ++#define SGPIO_G7_CTRL_REG_BASE 0x80 ++#define SGPIO_G7_CTRL_REG_OFFSET(x) (SGPIO_G7_CTRL_REG_BASE + (x) * 0x4) ++#define SGPIO_G7_OUT_DATA BIT(0) ++#define SGPIO_G7_PARALLEL_OUT_DATA BIT(1) ++#define SGPIO_G7_IRQ_EN BIT(2) ++#define SGPIO_G7_IRQ_TYPE0 BIT(3) ++#define SGPIO_G7_IRQ_TYPE1 BIT(4) ++#define SGPIO_G7_IRQ_TYPE2 BIT(5) ++#define SGPIO_G7_RST_TOLERANCE BIT(6) ++#define SGPIO_G7_INPUT_MASK BIT(9) ++#define SGPIO_G7_HW_BYPASS_EN BIT(10) ++#define SGPIO_G7_HW_IN_SEL BIT(11) ++#define SGPIO_G7_IRQ_STS BIT(12) ++#define SGPIO_G7_IN_DATA BIT(13) ++#define SGPIO_G7_PARALLEL_IN_DATA BIT(14) ++#define SGPIO_G7_SERIAL_OUT_SEL GENMASK(17, 16) ++#define SGPIO_G7_PARALLEL_OUT_SEL GENMASK(19, 18) ++#define SELECT_FROM_CSR 0 ++#define SELECT_FROM_PARALLEL_IN 1 ++#define SELECT_FROM_SERIAL_IN 2 + -+static const struct aspeed_gpio_config ast2700_config = -+ /* -+ * ast2700 has two controllers one with 212 GPIOs and one with 16 GPIOs. -+ * 216 for simplicity, actual number is 212 (4-GPIO hole in GPIOH) -+ * We expect ngpio being set in the device tree and this is a fallback -+ * option. -+ */ -+ { -+ .nr_gpios = 216, -+ .props = ast2700_bank_props, -+ .llops = &aspeed_g7_llops, -+ .debounce_timers_array = g7_debounce_timers, -+ .debounce_timers_num = ARRAY_SIZE(g7_debounce_timers), -+ .require_dcache = false, -+ }; - - static const struct of_device_id aspeed_gpio_of_table[] = { - { .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, }, - { .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, }, - { .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, }, -+ { .compatible = "aspeed,ast2700-gpio", .data = &ast2700_config, }, - {} - }; - MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table); - --static int __init aspeed_gpio_probe(struct platform_device *pdev) -+static int aspeed_gpio_probe(struct platform_device *pdev) - { - const struct of_device_id *gpio_id; - struct gpio_irq_chip *girq; -@@ -1202,6 +1361,10 @@ - - gpio->config = gpio_id->data; - -+ if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get || -+ !gpio->config->llops->reg_bank_get) -+ return -EINVAL; ++#define BMC_CONTROL_START_INDEX 128 ++#define BMC_CONTROL_END_INDEX 143 + - gpio->chip.parent = &pdev->dev; - err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio); - gpio->chip.ngpio = (u16) ngpio; -@@ -1218,27 +1381,23 @@ - gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.base = -1; ++#define ASPEED_SGPIO_G4_CFG_OFFSET 0x54 ++#define ASPEED_SGPIO_G7_CFG_OFFSET 0x0 -- /* Allocate a cache of the output registers */ -- banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); -- gpio->dcache = devm_kcalloc(&pdev->dev, -- banks, sizeof(u32), GFP_KERNEL); -- if (!gpio->dcache) -- return -ENOMEM; -- -- /* -- * Populate it with initial values read from the HW and switch -- * all command sources to the ARM by default -- */ -- for (i = 0; i < banks; i++) { -- const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; -- void __iomem *addr = bank_reg(gpio, bank, reg_rdata); -- gpio->dcache[i] = ioread32(addr); -- aspeed_gpio_change_cmd_source(gpio, bank, 0, GPIO_CMDSRC_ARM); -- aspeed_gpio_change_cmd_source(gpio, bank, 1, GPIO_CMDSRC_ARM); -- aspeed_gpio_change_cmd_source(gpio, bank, 2, GPIO_CMDSRC_ARM); -- aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM); -+ if (gpio->config->require_dcache) { -+ /* Allocate a cache of the output registers */ -+ banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); -+ gpio->dcache = devm_kcalloc(&pdev->dev, banks, sizeof(u32), GFP_KERNEL); -+ if (!gpio->dcache) -+ return -ENOMEM; -+ /* -+ * Populate it with initial values read from the HW -+ */ -+ for (i = 0; i < banks; i++) -+ gpio->dcache[i] = -+ gpio->config->llops->reg_bank_get(gpio, (i << 5), reg_rdata); - } + #define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) + #define ASPEED_SGPIO_ENABLE BIT(0) + #define ASPEED_SGPIO_PINS_SHIFT 6 -+ if (gpio->config->llops->privilege_init) -+ gpio->config->llops->privilege_init(gpio); ++#define ASPEED_SGPIO_G7_SERIAL_OUT_LOCK BIT(12) + - /* Set up an irqchip */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) -@@ -1270,13 +1429,14 @@ - } + struct aspeed_sgpio_pdata { + const u32 pin_mask; ++ const struct aspeed_sgpio_llops *llops; ++ const u32 cfg_offset; ++ const bool slave; + }; - static struct platform_driver aspeed_gpio_driver = { -+ .probe = aspeed_gpio_probe, - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = aspeed_gpio_of_table, - }, + struct aspeed_sgpio { +@@ -35,6 +72,7 @@ + raw_spinlock_t lock; + void __iomem *base; + int irq; ++ const struct aspeed_sgpio_pdata *pdata; }; --module_platform_driver_probe(aspeed_gpio_driver, aspeed_gpio_probe); -+module_platform_driver(aspeed_gpio_driver); + struct aspeed_sgpio_bank { +@@ -42,7 +80,6 @@ + u16 rdata_reg; + u16 irq_regs; + u16 tolerance_regs; +- const char names[4][3]; + }; - MODULE_DESCRIPTION("Aspeed GPIO Driver"); - MODULE_LICENSE("GPL"); -diff --git a/drivers/gpu/drm/aspeed/Kconfig b/drivers/gpu/drm/aspeed/Kconfig ---- a/drivers/gpu/drm/aspeed/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/Kconfig 2025-12-23 10:16:09.077234622 +0000 -@@ -4,6 +4,7 @@ - depends on DRM && OF - depends on (COMPILE_TEST || ARCH_ASPEED) - depends on MMU -+ select FB - select DRM_KMS_HELPER - select DRM_GEM_DMA_HELPER - select DMA_CMA if HAVE_DMA_CONTIGUOUS -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h ---- a/drivers/gpu/drm/aspeed/aspeed_gfx.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h 2025-12-23 10:16:20.986034982 +0000 -@@ -8,14 +8,31 @@ - struct drm_device drm; - void __iomem *base; - struct clk *clk; -- struct reset_control *rst; -+ struct reset_control *rst_crt; -+ struct reset_control *rst_engine; - struct regmap *scu; -+ struct regmap *dp; -+ struct regmap *dpmcu; -+ struct regmap *pcie_ep; -+ -+ u8 dp_support; -+ u8 pcie_advance; -+ u8 pcie_active; + /* +@@ -58,28 +95,24 @@ + .rdata_reg = 0x0070, + .irq_regs = 0x0004, + .tolerance_regs = 0x0018, +- .names = { "A", "B", "C", "D" }, + }, + { + .val_regs = 0x001C, + .rdata_reg = 0x0074, + .irq_regs = 0x0020, + .tolerance_regs = 0x0034, +- .names = { "E", "F", "G", "H" }, + }, + { + .val_regs = 0x0038, + .rdata_reg = 0x0078, + .irq_regs = 0x003C, + .tolerance_regs = 0x0050, +- .names = { "I", "J", "K", "L" }, + }, + { + .val_regs = 0x0090, + .rdata_reg = 0x007C, + .irq_regs = 0x0094, + .tolerance_regs = 0x00A8, +- .names = { "M", "N", "O", "P" }, + }, + }; - u32 dac_reg; - u32 int_clr_reg; - u32 vga_scratch_reg; - u32 throd_val; - u32 scan_line_max; -+ u32 flags; -+ u32 pcie_int_reg; -+ u32 pcie_int_mask; -+ u32 pcie_int_l_to_h; -+ u32 pcie_int_h_to_l; -+ u32 pcie_link_reg; -+ u32 pcie_link_bit; -+ u32 soc_crt_bit; -+ u32 soc_dp_bit; +@@ -92,6 +125,19 @@ + reg_irq_type2, + reg_irq_status, + reg_tolerance, ++ reg_serial_out_sel, ++ reg_parallel_out_sel, ++}; ++ ++struct aspeed_sgpio_llops { ++ void (*reg_bit_set)(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg, bool val); ++ bool (*reg_bit_get)(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg); ++ void (*reg_bank_set)(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg, u32 val); ++ int (*reg_bank_get)(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg); + }; - struct drm_simple_display_pipe pipe; - struct drm_connector connector; -@@ -106,3 +123,58 @@ - /* CRT_THROD */ - #define CRT_THROD_LOW(x) (x) - #define CRT_THROD_HIGH(x) ((x) << 8) -+ -+/* SCU control */ -+#define G4_DISABLE_D2_PLL BIT(4) -+#define G4_40_CLK 0x46314 -+#define G6_CLK_SOURCE 0x300 -+#define G6_CLK_SOURCE_MASK (BIT(8) | BIT(9) | BIT(10)) -+#define G6_CLK_SOURCE_HPLL (BIT(8) | BIT(9) | BIT(10)) -+#define G6_CLK_SOURCE_USB BIT(9) -+#define G6_CLK_SEL3 0x308 -+#define G6_CLK_DIV_MASK 0x3F000 -+#define G6_CLK_DIV_16 (BIT(16) | BIT(15) | BIT(13) | BIT(12)) -+#define G6_USB_40_CLK BIT(9) -+ -+/* GFX FLAGS */ -+#define RESET_MASK BIT(0) -+#define RESET_G6 BIT(0) -+#define CLK_MASK (BIT(4) | BIT(5) | BIT(6)) -+#define CLK_G4 BIT(4) -+#define CLK_G6 BIT(5) -+#define CLK_G7 BIT(6) -+#define ADDR_64 BIT(12) -+ -+/* PCIE interrupt */ -+#define PCIE_PERST_L_T_H_G5 BIT(18) -+#define PCIE_PERST_H_T_L_G5 BIT(19) -+#define PCIE_PERST_L_T_H_G7 BIT(2) -+#define PCIE_PERST_H_T_L_G7 BIT(3) -+ -+/* PCIE end pointer define */ -+#define PCIE_LINK_REG_G5 0xC0 -+#define PCIE_LINK_STATUS_G5 BIT(5) -+#define PCIE_LINK_REG_G7 0x358 -+#define PCIE_LINK_STATUS_G7 BIT(8) -+ -+/* Adaptor function define */ -+/* AST2600: DP adaptor define */ -+#define DP_26_CP_NAME "aspeed,ast2600-displayport" -+#define DP_26_MCU_CP_NAME "aspeed,ast2600-displayport-mcu" -+/* AST2600 */ -+#define SCU_DP_STATUS 0x100 /* SCU100 VGA function handshake */ -+/* AST2700: DP adaptor define */ -+#define DP_27_CP_NAME "aspeed,ast2700-displayport" -+#define DP_27_MCU_CP_NAME "aspeed,ast2700-displayport-mcu" -+#define SCU_PCIE0_DP_STATUS 0x900 /* SCU900 PCIE0 handshake */ -+#define SCU_PCIE1_DP_STATUS 0x910 /* SCU910 PCIE1 handshake */ -+#define DP_LOCATE_PCIE1 BIT(8) /* DP located on PCIE1 */ -+ -+/* AST DP */ -+#define DP_EXECUTE 0x2E /* DP Status */ -+#define DP_SOURCE 0xb8 /* DPB8 dp source */ -+#define DP_CONTROL_FROM_SOC (BIT(24) | BIT(28)) -+/* AST DP MCU */ -+#define DP_RESOLUTION 0xde0 /* DPMCUDE0 dp resolution */ -+#define DP_800 0x01050020 /* 800 x 600 60Hz */ -+#define DP_1024 0x010a0020 /* 1024 x 768 70Hz */ -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c ---- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c 2025-12-23 10:16:20.979035100 +0000 -@@ -23,6 +23,40 @@ - return container_of(pipe, struct aspeed_gfx, pipe); + #define GPIO_VAL_VALUE 0x00 +@@ -101,9 +147,9 @@ + #define GPIO_IRQ_TYPE2 0x0C + #define GPIO_IRQ_STATUS 0x10 + +-static void __iomem *bank_reg(struct aspeed_sgpio *gpio, +- const struct aspeed_sgpio_bank *bank, +- const enum aspeed_sgpio_reg reg) ++static void __iomem *aspeed_sgpio_g4_bank_reg(struct aspeed_sgpio *gpio, ++ const struct aspeed_sgpio_bank *bank, ++ const enum aspeed_sgpio_reg reg) + { + switch (reg) { + case reg_val: +@@ -128,6 +174,34 @@ + } } -+static void aspeed_gfx_set_g4_clock(struct aspeed_gfx *priv) -+{ -+ /* turn on d2 pll for soc disply at ast2400 */ -+ regmap_update_bits(priv->scu, priv->dac_reg, G4_DISABLE_D2_PLL, 0); -+ /* apply 800 x 600 @ 60 for soc disply at ast2400 */ -+ writel(G4_40_CLK, priv->base + CRT_MISC); -+} -+ -+static void aspeed_gfx_set_g6_clock_source(struct aspeed_gfx *priv, int mode_width) ++static u32 aspeed_sgpio_g7_reg_mask(const enum aspeed_sgpio_reg reg) +{ -+ regmap_update_bits(priv->scu, G6_CLK_SOURCE, G6_CLK_SOURCE_MASK, 0x0); -+ regmap_update_bits(priv->scu, G6_CLK_SEL3, G6_CLK_DIV_MASK, 0x0); -+ -+ switch (mode_width) { -+ case 1024: -+ /* hpll div 16 = 75Mhz */ -+ regmap_update_bits(priv->scu, G6_CLK_SOURCE, G6_CLK_SOURCE_MASK, G6_CLK_SOURCE_HPLL); -+ regmap_update_bits(priv->scu, G6_CLK_SEL3, G6_CLK_DIV_MASK, G6_CLK_DIV_16); -+ break; -+ case 800: -+ default: -+ /* usb 40Mhz */ -+ regmap_update_bits(priv->scu, G6_CLK_SOURCE, G6_CLK_SOURCE_MASK, G6_CLK_SOURCE_USB); -+ break; ++ switch (reg) { ++ case reg_val: ++ case reg_rdata: ++ return SGPIO_G7_OUT_DATA; ++ case reg_irq_enable: ++ return SGPIO_G7_IRQ_EN; ++ case reg_irq_type0: ++ return SGPIO_G7_IRQ_TYPE0; ++ case reg_irq_type1: ++ return SGPIO_G7_IRQ_TYPE1; ++ case reg_irq_type2: ++ return SGPIO_G7_IRQ_TYPE2; ++ case reg_irq_status: ++ return SGPIO_G7_IRQ_STS; ++ case reg_tolerance: ++ return SGPIO_G7_RST_TOLERANCE; ++ case reg_serial_out_sel: ++ return SGPIO_G7_SERIAL_OUT_SEL; ++ case reg_parallel_out_sel: ++ return SGPIO_G7_PARALLEL_OUT_SEL; ++ default: ++ WARN_ON_ONCE(1); ++ return 0; + } +} + -+static void aspeed_gfx_set_g7_clock(struct aspeed_gfx *priv) + #define GPIO_BANK(x) ((x) >> 6) + #define GPIO_OFFSET(x) ((x) & GENMASK(5, 0)) + #define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1) +@@ -166,20 +240,24 @@ + return !(offset % 2); + } + ++static bool aspeed_sgpios_ctrl_by_csr(unsigned int offset) +{ -+ /* apply 800 x 600 @ 62 on ast2700 */ -+ regmap_update_bits(priv->scu, 0x288, BIT(14), BIT(14)); -+ regmap_write(priv->scu, 0x340, 0x00130002); ++ if (offset >= BMC_CONTROL_START_INDEX && ++ offset <= BMC_CONTROL_END_INDEX) ++ return true; ++ return false; +} + - static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) + static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) { - struct drm_crtc *crtc = &priv->pipe.crtc; -@@ -59,8 +93,12 @@ - u32 ctrl1 = readl(priv->base + CRT_CTRL1); - u32 ctrl2 = readl(priv->base + CRT_CTRL2); + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_sgpio_bank *bank = to_bank(offset); +- unsigned long flags; + enum aspeed_sgpio_reg reg; + int rc = 0; -- /* Set DAC source for display output to Graphics CRT (GFX) */ -- regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), BIT(16)); -+ /* change the display source is coming from soc display */ -+ if (!priv->pcie_advance || !priv->pcie_active) { -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, priv->soc_crt_bit); -+ if (priv->dp_support) -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, priv->soc_dp_bit); -+ } +- raw_spin_lock_irqsave(&gpio->lock, flags); ++ guard(raw_spinlock_irqsave)(&gpio->lock); - writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1); - writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); -@@ -74,7 +112,42 @@ - writel(ctrl1 & ~CRT_CTRL_EN, priv->base + CRT_CTRL1); - writel(ctrl2 & ~CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); + reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; +- rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); +- +- raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ rc = gpio->pdata->llops->reg_bit_get(gpio, offset, reg); -- regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), 0); -+ /* Set display source for display output to pcie host display */ -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, 0); -+ if (priv->dp_support) -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, 0); -+} -+ -+static void aspeed_gfx_set_clk(struct aspeed_gfx *priv, int mode_width) -+{ -+ switch (priv->flags & CLK_MASK) { -+ case CLK_G4: -+ aspeed_gfx_set_g4_clock(priv); -+ break; -+ case CLK_G6: -+ aspeed_gfx_set_g6_clock_source(priv, mode_width); -+ break; -+ case CLK_G7: -+ aspeed_gfx_set_g7_clock(priv); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void aspeed_gfx_dp_mode_set(struct aspeed_gfx *priv, int mode_width) -+{ -+ switch (mode_width) { -+ case 1024: -+ /* hpll div 16 = 75Mhz */ -+ regmap_write(priv->dpmcu, DP_RESOLUTION, DP_1024); -+ break; -+ case 800: -+ default: -+ /* usb 40Mhz */ -+ regmap_write(priv->dpmcu, DP_RESOLUTION, DP_800); -+ break; -+ } + return rc; } +@@ -187,26 +265,11 @@ + static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) + { + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_sgpio_bank *bank = to_bank(offset); +- void __iomem *addr_r, *addr_w; +- u32 reg = 0; - static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) -@@ -87,6 +160,8 @@ - if (err) - return; + if (aspeed_sgpio_is_input(offset)) + return -EINVAL; -+ aspeed_gfx_set_clk(priv, m->hdisplay); -+ - #if 0 - /* TODO: we have only been able to test with the 40MHz USB clock. The - * clock is fixed, so we cannot adjust it here. */ -@@ -137,6 +212,10 @@ - * per line, rounded up) - */ - writel(priv->throd_val, priv->base + CRT_THROD); -+ -+ /* set the dp mode index */ -+ if (priv->dp_support) -+ aspeed_gfx_dp_mode_set(priv, m->hdisplay); +- /* Since this is an output, read the cached value from rdata, then +- * update val. */ +- addr_r = bank_reg(gpio, bank, reg_rdata); +- addr_w = bank_reg(gpio, bank, reg_val); +- +- reg = ioread32(addr_r); +- +- if (val) +- reg |= GPIO_BIT(offset); +- else +- reg &= ~GPIO_BIT(offset); +- +- iowrite32(reg, addr_w); ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val); + + return 0; } +@@ -214,13 +277,11 @@ + static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) + { + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); +- unsigned long flags; +- +- raw_spin_lock_irqsave(&gpio->lock, flags); - static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe *pipe, -@@ -187,12 +266,17 @@ - gem = drm_fb_dma_get_gem_obj(fb, 0); - if (!gem) - return; -- writel(gem->dma_addr, priv->base + CRT_ADDR); -+ -+ if (priv->flags & ADDR_64) -+ writel((gem->dma_addr >> 2), priv->base + CRT_ADDR); -+ else -+ writel(gem->dma_addr, priv->base + CRT_ADDR); ++ guard(raw_spinlock_irqsave)(&gpio->lock); + sgpio_set_value(gc, offset, val); + +- raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ return; } - static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) + static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) +@@ -231,15 +292,14 @@ + static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); +- unsigned long flags; + int rc; + + /* No special action is required for setting the direction; we'll + * error-out in sgpio_set_value if this isn't an output GPIO */ + +- raw_spin_lock_irqsave(&gpio->lock, flags); ++ guard(raw_spinlock_irqsave)(&gpio->lock); + - u32 reg = readl(priv->base + CRT_CTRL1); + rc = sgpio_set_value(gc, offset, val); +- raw_spin_unlock_irqrestore(&gpio->lock, flags); - /* Clear pending VBLANK IRQ */ -@@ -207,6 +291,7 @@ - static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) + return rc; + } +@@ -249,75 +309,33 @@ + return !!aspeed_sgpio_is_input(offset); + } + +-static void irqd_to_aspeed_sgpio_data(struct irq_data *d, +- struct aspeed_sgpio **gpio, +- const struct aspeed_sgpio_bank **bank, +- u32 *bit, int *offset) +-{ +- struct aspeed_sgpio *internal; +- +- *offset = irqd_to_hwirq(d); +- internal = irq_data_get_irq_chip_data(d); +- WARN_ON(!internal); +- +- *gpio = internal; +- *bank = to_bank(*offset); +- *bit = GPIO_BIT(*offset); +-} +- + static void aspeed_sgpio_irq_ack(struct irq_data *d) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); -+ - u32 reg = readl(priv->base + CRT_CTRL1); +- const struct aspeed_sgpio_bank *bank; +- struct aspeed_sgpio *gpio; +- unsigned long flags; +- void __iomem *status_addr; +- int offset; +- u32 bit; +- +- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); +- +- status_addr = bank_reg(gpio, bank, reg_irq_status); ++ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); ++ int offset = irqd_to_hwirq(d); - reg &= ~CRT_CTRL_VERTICAL_INTR_EN; -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c ---- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c 2025-12-23 10:16:20.992034882 +0000 -@@ -63,6 +63,15 @@ - u32 vga_scratch_reg; /* VGA scratch register in SCU */ - u32 throd_val; /* Default Threshold Seting */ - u32 scan_line_max; /* Max memory size of one scan line */ -+ u32 gfx_flags; /* Flags for gfx chip caps */ -+ u32 pcie_int_reg; /* pcie interrupt */ -+ u32 pcie_int_mask; /* pcie PERST# mask */ -+ u32 pcie_int_l_to_h; /* pcie PERST# low to high */ -+ u32 pcie_int_h_to_l; /* pcie PERST# high to low */ -+ u32 pcie_link_reg; /* pcie link status offset */ -+ u32 pcie_link_bit; /* pcie link status bit */ -+ u32 soc_crt_bit; /* soc display crt switch flag*/ -+ u32 soc_dp_bit; /* soc display dp switch flag*/ - }; +- raw_spin_lock_irqsave(&gpio->lock, flags); ++ guard(raw_spinlock_irqsave)(&gpio->lock); - static const struct aspeed_gfx_config ast2400_config = { -@@ -71,6 +80,15 @@ - .vga_scratch_reg = 0x50, - .throd_val = CRT_THROD_LOW(0x1e) | CRT_THROD_HIGH(0x12), - .scan_line_max = 64, -+ .gfx_flags = CLK_G4, -+ .pcie_int_reg = 0x0, -+ .pcie_int_mask = 0x0, -+ .pcie_int_l_to_h = 0x0, -+ .pcie_int_h_to_l = 0x0, -+ .pcie_link_reg = 0x0, -+ .pcie_link_bit = 0x0, -+ .soc_crt_bit = BIT(16), -+ .soc_dp_bit = 0x0, - }; +- iowrite32(bit, status_addr); +- +- raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); + } - static const struct aspeed_gfx_config ast2500_config = { -@@ -79,6 +97,15 @@ - .vga_scratch_reg = 0x50, - .throd_val = CRT_THROD_LOW(0x24) | CRT_THROD_HIGH(0x3c), - .scan_line_max = 128, -+ .gfx_flags = 0, -+ .pcie_int_reg = 0x18, -+ .pcie_int_mask = (PCIE_PERST_L_T_H_G5 | PCIE_PERST_H_T_L_G5), -+ .pcie_int_l_to_h = PCIE_PERST_L_T_H_G5, -+ .pcie_int_h_to_l = PCIE_PERST_H_T_L_G5, -+ .pcie_link_reg = PCIE_LINK_REG_G5, -+ .pcie_link_bit = PCIE_LINK_STATUS_G5, -+ .soc_crt_bit = BIT(16), -+ .soc_dp_bit = 0x0, - }; + static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) + { +- const struct aspeed_sgpio_bank *bank; +- struct aspeed_sgpio *gpio; +- unsigned long flags; +- u32 reg, bit; +- void __iomem *addr; +- int offset; +- +- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); +- addr = bank_reg(gpio, bank, reg_irq_enable); ++ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); ++ int offset = irqd_to_hwirq(d); - static const struct aspeed_gfx_config ast2600_config = { -@@ -87,12 +114,39 @@ - .vga_scratch_reg = 0x50, - .throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70), - .scan_line_max = 128, -+ .gfx_flags = RESET_G6 | CLK_G6, -+ .pcie_int_reg = 0x560, -+ .pcie_int_mask = (PCIE_PERST_L_T_H_G5 | PCIE_PERST_H_T_L_G5), -+ .pcie_int_l_to_h = PCIE_PERST_L_T_H_G5, -+ .pcie_int_h_to_l = PCIE_PERST_H_T_L_G5, -+ .pcie_link_reg = PCIE_LINK_REG_G5, -+ .pcie_link_bit = PCIE_LINK_STATUS_G5, -+ .soc_crt_bit = BIT(16), -+ .soc_dp_bit = BIT(18), -+}; -+ -+static const struct aspeed_gfx_config ast2700_config = { -+ .dac_reg = 0x414, -+ .int_clear_reg = 0x68, -+ .vga_scratch_reg = 0x50, -+ .throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70), -+ .scan_line_max = 128, -+ .gfx_flags = CLK_G7 | ADDR_64, -+ .pcie_int_reg = 0x1D0, -+ .pcie_int_mask = (PCIE_PERST_L_T_H_G7 | PCIE_PERST_H_T_L_G7), -+ .pcie_int_l_to_h = PCIE_PERST_L_T_H_G7, -+ .pcie_int_h_to_l = PCIE_PERST_H_T_L_G7, -+ .pcie_link_reg = PCIE_LINK_REG_G7, -+ .pcie_link_bit = PCIE_LINK_STATUS_G7, -+ .soc_crt_bit = BIT(11), -+ .soc_dp_bit = BIT(9), - }; + /* Unmasking the IRQ */ + if (set) +- gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); +- +- raw_spin_lock_irqsave(&gpio->lock, flags); +- +- reg = ioread32(addr); +- if (set) +- reg |= bit; +- else +- reg &= ~bit; +- +- iowrite32(reg, addr); +- +- raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ gpiochip_enable_irq(&gpio->chip, offset); ++ scoped_guard(raw_spinlock_irqsave, &gpio->lock) ++ { ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_enable, ++ set); ++ } - static const struct of_device_id aspeed_gfx_match[] = { - { .compatible = "aspeed,ast2400-gfx", .data = &ast2400_config }, - { .compatible = "aspeed,ast2500-gfx", .data = &ast2500_config }, - { .compatible = "aspeed,ast2600-gfx", .data = &ast2600_config }, -+ { .compatible = "aspeed,ast2700-gfx", .data = &ast2700_config }, - { }, - }; - MODULE_DEVICE_TABLE(of, aspeed_gfx_match); -@@ -105,6 +159,7 @@ + /* Masking the IRQ */ + if (!set) +- gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); +- +- ++ gpiochip_disable_irq(&gpio->chip, offset); + } - static int aspeed_gfx_setup_mode_config(struct drm_device *drm) + static void aspeed_sgpio_irq_mask(struct irq_data *d) +@@ -335,55 +353,36 @@ + u32 type0 = 0; + u32 type1 = 0; + u32 type2 = 0; +- u32 bit, reg; +- const struct aspeed_sgpio_bank *bank; + irq_flow_handler_t handler; +- struct aspeed_sgpio *gpio; +- unsigned long flags; +- void __iomem *addr; +- int offset; +- +- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); ++ int offset = irqd_to_hwirq(d); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: +- type2 |= bit; ++ type2 = 1; + fallthrough; + case IRQ_TYPE_EDGE_RISING: +- type0 |= bit; ++ type0 = 1; + fallthrough; + case IRQ_TYPE_EDGE_FALLING: + handler = handle_edge_irq; + break; + case IRQ_TYPE_LEVEL_HIGH: +- type0 |= bit; ++ type0 = 1; + fallthrough; + case IRQ_TYPE_LEVEL_LOW: +- type1 |= bit; ++ type1 = 1; + handler = handle_level_irq; + break; + default: + return -EINVAL; + } + +- raw_spin_lock_irqsave(&gpio->lock, flags); +- +- addr = bank_reg(gpio, bank, reg_irq_type0); +- reg = ioread32(addr); +- reg = (reg & ~bit) | type0; +- iowrite32(reg, addr); +- +- addr = bank_reg(gpio, bank, reg_irq_type1); +- reg = ioread32(addr); +- reg = (reg & ~bit) | type1; +- iowrite32(reg, addr); +- +- addr = bank_reg(gpio, bank, reg_irq_type2); +- reg = ioread32(addr); +- reg = (reg & ~bit) | type2; +- iowrite32(reg, addr); +- +- raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ scoped_guard(raw_spinlock_irqsave, &gpio->lock) { ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); ++ } + + irq_set_handler_locked(d, handler); + +@@ -395,15 +394,14 @@ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct aspeed_sgpio *data = gpiochip_get_data(gc); +- unsigned int i, p; ++ unsigned int i, p, banks; + unsigned long reg; + + chained_irq_enter(ic, desc); + +- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { +- const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; +- +- reg = ioread32(bank_reg(data, bank, reg_irq_status)); ++ banks = DIV_ROUND_UP(gc->ngpio, 64); ++ for (i = 0; i < banks; i++) { ++ reg = data->pdata->llops->reg_bank_get(data, i << 6, reg_irq_status); + + for_each_set_bit(p, ®, 32) + generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2); +@@ -414,13 +412,9 @@ + + static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) { -+ struct aspeed_gfx *priv = to_aspeed_gfx(drm); - int ret; +- const struct aspeed_sgpio_bank *bank; +- struct aspeed_sgpio *gpio; +- u32 bit; +- int offset; ++ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); - ret = drmm_mode_config_init(drm); -@@ -113,13 +168,63 @@ +- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); +- seq_printf(p, dev_name(gpio->dev)); ++ seq_puts(p, dev_name(gpio->dev)); + } - drm->mode_config.min_width = 0; - drm->mode_config.min_height = 0; -- drm->mode_config.max_width = 800; -- drm->mode_config.max_height = 600; + static const struct irq_chip aspeed_sgpio_irq_chip = { +@@ -437,7 +431,6 @@ + struct platform_device *pdev) + { + int rc, i; +- const struct aspeed_sgpio_bank *bank; + struct gpio_irq_chip *irq; + + rc = platform_get_irq(pdev, 0); +@@ -447,12 +440,11 @@ + gpio->irq = rc; + + /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ +- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { +- bank = &aspeed_sgpio_banks[i]; ++ for (i = 0; i < gpio->chip.ngpio; i += 2) { + /* disable irq enable bits */ +- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); ++ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_enable, 0); + /* clear status bits */ +- iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); ++ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_status, 1); + } + + irq = &gpio->chip.irq; +@@ -466,45 +458,98 @@ + irq->num_parents = 1; + + /* Apply default IRQ settings */ +- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { +- bank = &aspeed_sgpio_banks[i]; ++ for (i = 0; i < gpio->chip.ngpio; i += 2) { + /* set falling or level-low irq */ +- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); ++ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type0, 0); + /* trigger type is edge */ +- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); ++ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type1, 0); + /* single edge trigger */ +- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); ++ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type2, 0); + } + + return 0; + } + ++static void aspeed_sgpio_g4_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg, bool val) ++{ ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); ++ u32 temp; + -+ switch (priv->flags & CLK_MASK) { -+ case CLK_G6: -+ drm->mode_config.max_width = 1024; -+ drm->mode_config.max_height = 768; -+ break; -+ default: -+ drm->mode_config.max_width = 800; -+ drm->mode_config.max_height = 600; -+ break; ++ if (reg == reg_val) { ++ /* Since this is an output, read the cached value from rdata, then update val. */ ++ addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_rdata); ++ temp = ioread32(addr); ++ if (val) ++ temp |= GPIO_BIT(offset); ++ else ++ temp &= ~GPIO_BIT(offset); ++ ++ addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_val); ++ iowrite32(temp, addr); ++ } else if (reg == reg_irq_status) { ++ if (val) ++ iowrite32(GPIO_BIT(offset), addr); ++ } else { ++ /* When setting other registers, we read from the register itself */ ++ temp = ioread32(addr); ++ if (val) ++ temp |= GPIO_BIT(offset); ++ else ++ temp &= ~GPIO_BIT(offset); ++ iowrite32(temp, addr); + } ++} + - drm->mode_config.funcs = &aspeed_gfx_mode_config_funcs; ++static bool aspeed_sgpio_g4_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg) ++{ ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); ++ ++ return !!(ioread32(addr) & GPIO_BIT(offset)); ++} ++ ++static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg) ++{ ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); ++ ++ if (reg == reg_irq_status) ++ return ioread32(addr); ++ else ++ return -EOPNOTSUPP; ++} ++ ++static void aspeed_sgpio_g4_reg_bank_set(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg, u32 val) ++{ ++ /* G4 doesn't support bank set for now */ ++} ++ ++static const struct aspeed_sgpio_llops aspeed_sgpio_g4_llops = { ++ .reg_bit_set = aspeed_sgpio_g4_reg_bit_set, ++ .reg_bit_get = aspeed_sgpio_g4_reg_bit_get, ++ .reg_bank_set = aspeed_sgpio_g4_reg_bank_set, ++ .reg_bank_get = aspeed_sgpio_g4_reg_bank_get, ++}; ++ + static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { + .pin_mask = GENMASK(9, 6), ++ .llops = &aspeed_sgpio_g4_llops, ++ .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET, + }; - return ret; + static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, + unsigned int offset, bool enable) + { + struct aspeed_sgpio *gpio = gpiochip_get_data(chip); +- unsigned long flags; +- void __iomem *reg; +- u32 val; +- +- reg = bank_reg(gpio, to_bank(offset), reg_tolerance); +- +- raw_spin_lock_irqsave(&gpio->lock, flags); +- +- val = readl(reg); +- +- if (enable) +- val |= GPIO_BIT(offset); +- else +- val &= ~GPIO_BIT(offset); + +- writel(val, reg); ++ guard(raw_spinlock_irqsave)(&gpio->lock); + +- raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); + + return 0; } +@@ -523,12 +568,151 @@ -+static irqreturn_t aspeed_host_irq_handler(int irq, void *data) -+{ -+ struct drm_device *drm = data; -+ struct aspeed_gfx *priv = to_aspeed_gfx(drm); -+ u32 reg; + static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { + .pin_mask = GENMASK(10, 6), ++ .llops = &aspeed_sgpio_g4_llops, ++ .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET, ++}; + -+ regmap_read(priv->scu, priv->pcie_int_reg, ®); ++static void aspeed_sgpio_g7_serial_out_lock(struct aspeed_sgpio *gpio, bool lock) ++{ ++ void __iomem *cfg = gpio->base + gpio->pdata->cfg_offset; ++ u32 val = ioread32(cfg); + -+ if (reg & priv->pcie_int_mask) { -+ if (reg & priv->pcie_int_l_to_h) { -+ dev_dbg(drm->dev, "pcie active.\n"); -+ /*Change the DP back to host*/ -+ if (priv->dp_support) { -+ /*Change the DP back to host*/ -+ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, 0); -+ dev_dbg(drm->dev, "dp set at 0 int L_T_H.\n"); -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, 0); -+ } ++ if (lock) ++ val |= ASPEED_SGPIO_G7_SERIAL_OUT_LOCK; ++ else ++ val &= ~ASPEED_SGPIO_G7_SERIAL_OUT_LOCK; ++ iowrite32(val, cfg); ++} + -+ /*Change the CRT back to host*/ -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, 0); -+ } else if (reg & priv->pcie_int_h_to_l) { -+ dev_dbg(drm->dev, "pcie de-active.\n"); -+ /*Change the DP into host*/ -+ if (priv->dp_support) { -+ /*Change the DP back to soc*/ -+ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); -+ dev_dbg(drm->dev, "dp set at 11 int H_T_L.\n"); -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, priv->soc_dp_bit); -+ } ++static void aspeed_sgpio_g7_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg, bool val) ++{ ++ u32 mask = aspeed_sgpio_g7_reg_mask(reg); ++ void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); ++ bool serial_out = false; ++ u32 write_val; + -+ /*Change the CRT into soc*/ -+ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, priv->soc_crt_bit); ++ if (reg == reg_val || reg == reg_rdata) { ++ if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) { ++ // Ensure the parallel out value control by the software. ++ gpio->pdata->llops->reg_bank_set(gpio, offset, reg_parallel_out_sel, ++ SELECT_FROM_CSR); ++ mask = SGPIO_G7_PARALLEL_OUT_DATA; ++ } else { ++ // Ensure the serial out value control by the software. ++ gpio->pdata->llops->reg_bank_set(gpio, offset, reg_serial_out_sel, ++ SELECT_FROM_CSR); ++ mask = SGPIO_G7_OUT_DATA; ++ serial_out = (reg == reg_val); + } -+ return IRQ_HANDLED; + } + -+ return IRQ_NONE; ++ if (mask) { ++ /* ++ * Freeze the serial-out shifter across the value update so a ++ * half-written level can never be clocked out mid-waveform, ++ * then release it once the new value is in place. ++ */ ++ if (serial_out) ++ aspeed_sgpio_g7_serial_out_lock(gpio, true); ++ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); ++ iowrite32(write_val, addr); ++ if (serial_out) ++ aspeed_sgpio_g7_serial_out_lock(gpio, false); ++ } +} + - static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) - { - struct drm_device *drm = data; -@@ -137,6 +242,145 @@ - return IRQ_NONE; - } - -+static int aspeed_pcie_active_detect(struct drm_device *drm) ++static bool aspeed_sgpio_g7_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg) +{ -+ struct aspeed_gfx *priv = to_aspeed_gfx(drm); -+ u32 reg = 0; ++ u32 mask = aspeed_sgpio_g7_reg_mask(reg); ++ void __iomem *addr; + -+ /* map pcie ep resource */ -+ priv->pcie_ep = syscon_regmap_lookup_by_compatible("aspeed,ast2500-pcie-ep"); -+ if (IS_ERR(priv->pcie_ep)) { -+ priv->pcie_ep = syscon_regmap_lookup_by_compatible("aspeed,ast2600-pcie-phy"); -+ if (IS_ERR(priv->pcie_ep)) { -+ priv->pcie_ep = syscon_regmap_lookup_by_compatible("aspeed,ast2700-pcie-phy"); -+ if (IS_ERR(priv->pcie_ep)) { -+ dev_err(drm->dev, "failed to find pcie_ep regmap\n"); -+ return PTR_ERR(priv->pcie_ep); -+ } ++ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); ++ if (reg == reg_val) { ++ if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) { ++ unsigned int pin = offset >> 1; ++ ++ /* ++ * Slave pins 15:0 split their input source: data[3:0] ++ * (pins 0..3) come from the parallel-in pads, while ++ * data[15:4] (pins 4..15) are sampled from the serial ++ * input stream driven by the master. ++ */ ++ if (pin >= 4 && pin <= 15) ++ mask = SGPIO_G7_IN_DATA; ++ else ++ mask = SGPIO_G7_PARALLEL_IN_DATA; ++ } else { ++ mask = SGPIO_G7_IN_DATA; + } + } + -+ /* check pcie rst status */ -+ regmap_read(priv->pcie_ep, priv->pcie_link_reg, ®); ++ if (reg == reg_rdata) { ++ if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) ++ mask = SGPIO_G7_PARALLEL_OUT_DATA; ++ else ++ mask = SGPIO_G7_OUT_DATA; ++ } + -+ /* host vga is on or not */ -+ if (reg & priv->pcie_link_bit) -+ priv->pcie_active = 0x1; ++ if (mask) ++ return field_get(mask, ioread32(addr)); + else -+ priv->pcie_active = 0x0; ++ return 0; ++} + -+ dev_dbg(drm->dev, "pcie_active %x\n", priv->pcie_active); ++static int aspeed_sgpio_g7_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg) ++{ ++ void __iomem *addr; + -+ return 0; ++ if (reg == reg_irq_status) { ++ addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(offset >> 6); ++ return ioread32(addr); ++ } else { ++ return -EOPNOTSUPP; ++ } +} + -+static int aspeed_adaptor_detect(struct drm_device *drm) ++static void aspeed_sgpio_g7_reg_bank_set(struct aspeed_sgpio *gpio, unsigned int offset, ++ const enum aspeed_sgpio_reg reg, u32 val) +{ -+ struct aspeed_gfx *priv = to_aspeed_gfx(drm); -+ u32 dp_status_offset = 0, reg = 0; ++ void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); ++ u32 mask, write_val; + -+ switch (priv->flags & CLK_MASK) { -+ case CLK_G6: -+ /* check AST DP is executed or not*/ -+ regmap_read(priv->scu, SCU_DP_STATUS, ®); -+ if (((reg >> 8) & DP_EXECUTE) == DP_EXECUTE) { -+ priv->dp_support = 0x1; ++ if (reg == reg_serial_out_sel || reg == reg_parallel_out_sel) { ++ mask = aspeed_sgpio_g7_reg_mask(reg); ++ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); ++ iowrite32(write_val, addr); ++ } ++} + -+ priv->dp = syscon_regmap_lookup_by_compatible(DP_26_CP_NAME); -+ if (IS_ERR(priv->dp)) { -+ dev_err(drm->dev, "failed to find DP regmap\n"); -+ return PTR_ERR(priv->dp); -+ } ++static const struct aspeed_sgpio_llops aspeed_sgpio_g7_llops = { ++ .reg_bit_set = aspeed_sgpio_g7_reg_bit_set, ++ .reg_bit_get = aspeed_sgpio_g7_reg_bit_get, ++ .reg_bank_set = aspeed_sgpio_g7_reg_bank_set, ++ .reg_bank_get = aspeed_sgpio_g7_reg_bank_get, ++}; + -+ priv->dpmcu = syscon_regmap_lookup_by_compatible(DP_26_MCU_CP_NAME); -+ if (IS_ERR(priv->dpmcu)) { -+ dev_err(drm->dev, "failed to find DP MCU regmap\n"); -+ return PTR_ERR(priv->dpmcu); -+ } ++static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = { ++ .pin_mask = GENMASK(11, 6), ++ .llops = &aspeed_sgpio_g7_llops, ++ .cfg_offset = ASPEED_SGPIO_G7_CFG_OFFSET, ++}; + -+ /* change the dp setting is coming from soc display */ -+ if (!priv->pcie_active) -+ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); ++static const struct aspeed_sgpio_pdata ast2700_sgpios_pdata = { ++ .pin_mask = GENMASK(11, 6), ++ .llops = &aspeed_sgpio_g7_llops, ++ .cfg_offset = ASPEED_SGPIO_G7_CFG_OFFSET, ++ .slave = true, + }; + + static const struct of_device_id aspeed_sgpio_of_table[] = { + { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, }, + { .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, }, + { .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, }, ++ { .compatible = "aspeed,ast2700-sgpiom", .data = &ast2700_sgpiom_pdata, }, ++ { .compatible = "aspeed,ast2700-sgpios", .data = &ast2700_sgpios_pdata, }, + {} + }; + +@@ -537,7 +721,6 @@ + static int aspeed_sgpio_probe(struct platform_device *pdev) + { + u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask; +- const struct aspeed_sgpio_pdata *pdata; + struct aspeed_sgpio *gpio; + unsigned long apb_freq; + int rc; +@@ -552,12 +735,11 @@ + + gpio->dev = &pdev->dev; + +- pdata = device_get_match_data(&pdev->dev); +- if (!pdata) ++ gpio->pdata = device_get_match_data(&pdev->dev); ++ if (!gpio->pdata) + return -EINVAL; + +- pin_mask = pdata->pin_mask; +- ++ pin_mask = gpio->pdata->pin_mask; + rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); + if (rc < 0) { + dev_err(&pdev->dev, "Could not read ngpios property\n"); +@@ -568,40 +750,50 @@ + return -EINVAL; + } + +- rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); +- if (rc < 0) { +- dev_err(&pdev->dev, "Could not read bus-frequency property\n"); +- return -EINVAL; +- } +- +- gpio->pclk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(gpio->pclk)) { +- dev_err(&pdev->dev, "devm_clk_get failed\n"); +- return PTR_ERR(gpio->pclk); +- } +- +- apb_freq = clk_get_rate(gpio->pclk); +- +- /* +- * From the datasheet, +- * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) +- * period = 2 * (GPIO254[31:16] + 1) / PCLK +- * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) +- * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) +- * frequency * 2 * (GPIO254[31:16] + 1) = PCLK +- * GPIO254[31:16] = PCLK / (frequency * 2) - 1 +- */ +- if (sgpio_freq == 0) +- return -EINVAL; +- +- sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; +- +- if (sgpio_clk_div > (1 << 16) - 1) +- return -EINVAL; ++ if (!gpio->pdata->slave) { ++ int i; + +- gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; +- iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | +- ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL); ++ for (i = 0; i < nr_gpios; i++) ++ gpio->pdata->llops->reg_bank_set(gpio, i << 1, reg_serial_out_sel, ++ SELECT_FROM_CSR); ++ ++ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "Could not read bus-frequency property\n"); ++ return -EINVAL; + } -+ break; -+ case CLK_G7: -+ /* check AST DP is located on PCIE0 or PCIE1 */ -+ regmap_read(priv->scu, priv->dac_reg, ®); + -+ if (reg & DP_LOCATE_PCIE1) -+ dp_status_offset = SCU_PCIE1_DP_STATUS; -+ else -+ dp_status_offset = SCU_PCIE0_DP_STATUS; ++ gpio->pclk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(gpio->pclk)) { ++ dev_err(&pdev->dev, "devm_clk_get failed\n"); ++ return PTR_ERR(gpio->pclk); ++ } + -+ /* check AST DP is executed or not*/ -+ regmap_read(priv->scu, dp_status_offset, ®); -+ if (((reg >> 8) & DP_EXECUTE) == DP_EXECUTE) { -+ priv->dp_support = 0x1; ++ apb_freq = clk_get_rate(gpio->pclk); + -+ priv->dp = syscon_regmap_lookup_by_compatible(DP_27_CP_NAME); -+ if (IS_ERR(priv->dp)) { -+ dev_err(drm->dev, "failed to find DP regmap\n"); -+ return PTR_ERR(priv->dp); -+ } ++ /* ++ * From the datasheet, ++ * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) ++ * period = 2 * (GPIO254[31:16] + 1) / PCLK ++ * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) ++ * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) ++ * frequency * 2 * (GPIO254[31:16] + 1) = PCLK ++ * GPIO254[31:16] = PCLK / (frequency * 2) - 1 ++ */ ++ if (sgpio_freq == 0) ++ return -EINVAL; + -+ priv->dpmcu = syscon_regmap_lookup_by_compatible(DP_27_MCU_CP_NAME); -+ if (IS_ERR(priv->dpmcu)) { -+ dev_err(drm->dev, "failed to find DP MCU regmap\n"); -+ return PTR_ERR(priv->dpmcu); -+ } ++ sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; + -+ /* change the dp setting is coming from soc display */ -+ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); -+ } ++ if (sgpio_clk_div > (1 << 16) - 1) ++ return -EINVAL; + -+ break; -+ default: -+ priv->dp_support = 0x0; -+ priv->dp = NULL; -+ priv->dpmcu = NULL; -+ break; ++ gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; ++ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | ++ ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset); ++ } else { ++ iowrite32(ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset); + } -+ return 0; -+} + + raw_spin_lock_init(&gpio->lock); + +diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c +--- a/drivers/gpio/gpio-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpio/gpio-aspeed.c 2026-09-09 15:51:44.631239386 +0000 +@@ -30,6 +30,27 @@ + #include + #include "gpiolib.h" + ++/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ ++#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) ++#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + -+static int aspeed_gfx_reset(struct drm_device *drm) -+{ -+ struct platform_device *pdev = to_platform_device(drm->dev); -+ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++#define GPIO_G7_IRQ_STS_BASE 0x100 ++#define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4) ++#define GPIO_G7_CTRL_REG_BASE 0x180 ++#define GPIO_G7_CTRL_REG_OFFSET(x) (GPIO_G7_CTRL_REG_BASE + (x) * 0x4) ++#define GPIO_G7_CTRL_OUT_DATA BIT(0) ++#define GPIO_G7_CTRL_DIR BIT(1) ++#define GPIO_G7_CTRL_IRQ_EN BIT(2) ++#define GPIO_G7_CTRL_IRQ_TYPE0 BIT(3) ++#define GPIO_G7_CTRL_IRQ_TYPE1 BIT(4) ++#define GPIO_G7_CTRL_IRQ_TYPE2 BIT(5) ++#define GPIO_G7_CTRL_RST_TOLERANCE BIT(6) ++#define GPIO_G7_CTRL_DEBOUNCE_SEL2 BIT(7) ++#define GPIO_G7_CTRL_DEBOUNCE_SEL1 BIT(8) ++#define GPIO_G7_CTRL_INPUT_MASK BIT(9) ++#define GPIO_G7_CTRL_IRQ_STS BIT(12) ++#define GPIO_G7_CTRL_IN_DATA BIT(13) + -+ switch (priv->flags & RESET_MASK) { -+ case RESET_G6: -+ priv->rst_crt = devm_reset_control_get(&pdev->dev, "crt"); -+ if (IS_ERR(priv->rst_crt)) { -+ dev_err(&pdev->dev, -+ "missing or invalid crt reset controller device tree entry"); -+ return PTR_ERR(priv->rst_crt); -+ } -+ reset_control_deassert(priv->rst_crt); + struct aspeed_bank_props { + unsigned int bank; + u32 input; +@@ -39,6 +60,10 @@ + struct aspeed_gpio_config { + unsigned int nr_gpios; + const struct aspeed_bank_props *props; ++ const struct aspeed_gpio_llops *llops; ++ const int *debounce_timers_array; ++ int debounce_timers_num; ++ bool require_dcache; + }; + + /* +@@ -77,7 +102,6 @@ + uint16_t debounce_regs; + uint16_t tolerance_regs; + uint16_t cmdsrc_regs; +- const char names[4][3]; + }; + + /* +@@ -92,6 +116,22 @@ + */ + + static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; ++static const int g7_debounce_timers[4] = { 0x00, 0x00, 0x04, 0x08 }; + -+ priv->rst_engine = devm_reset_control_get(&pdev->dev, "engine"); -+ if (IS_ERR(priv->rst_engine)) { -+ dev_err(&pdev->dev, -+ "missing or invalid engine reset controller device tree entry"); -+ return PTR_ERR(priv->rst_engine); -+ } -+ reset_control_deassert(priv->rst_engine); -+ break; ++/* ++ * The debounce timers array is used to configure the debounce timer settings.Here’s how it works: ++ * Array Value: Indicates the offset for configuring the debounce timer. ++ * Array Index: Corresponds to the debounce setting register. ++ * The debounce timers array follows this pattern for configuring the debounce setting registers: ++ * Array Index 0: No debounce timer is set; ++ * Array Value is irrelevant (don’t care). ++ * Array Index 1: Debounce setting #2 is set to 1, and debounce setting #1 is set to 0. ++ * Array Value: offset for configuring debounce timer 0 (g4: 0x50, g7: 0x00) ++ * Array Index 2: Debounce setting #2 is set to 0, and debounce setting #1 is set to 1. ++ * Array Value: offset for configuring debounce timer 1 (g4: 0x54, g7: 0x04) ++ * Array Index 3: Debounce setting #2 is set to 1, and debounce setting #1 is set to 1. ++ * Array Value: offset for configuring debounce timer 2 (g4: 0x58, g7: 0x8) ++ */ + + static const struct aspeed_gpio_copro_ops *copro_ops; + static void *copro_data; +@@ -104,7 +144,6 @@ + .debounce_regs = 0x0040, + .tolerance_regs = 0x001c, + .cmdsrc_regs = 0x0060, +- .names = { "A", "B", "C", "D" }, + }, + { + .val_regs = 0x0020, +@@ -113,7 +152,6 @@ + .debounce_regs = 0x0048, + .tolerance_regs = 0x003c, + .cmdsrc_regs = 0x0068, +- .names = { "E", "F", "G", "H" }, + }, + { + .val_regs = 0x0070, +@@ -122,7 +160,6 @@ + .debounce_regs = 0x00b0, + .tolerance_regs = 0x00ac, + .cmdsrc_regs = 0x0090, +- .names = { "I", "J", "K", "L" }, + }, + { + .val_regs = 0x0078, +@@ -131,7 +168,6 @@ + .debounce_regs = 0x0100, + .tolerance_regs = 0x00fc, + .cmdsrc_regs = 0x00e0, +- .names = { "M", "N", "O", "P" }, + }, + { + .val_regs = 0x0080, +@@ -140,7 +176,6 @@ + .debounce_regs = 0x0130, + .tolerance_regs = 0x012c, + .cmdsrc_regs = 0x0110, +- .names = { "Q", "R", "S", "T" }, + }, + { + .val_regs = 0x0088, +@@ -149,7 +184,6 @@ + .debounce_regs = 0x0160, + .tolerance_regs = 0x015c, + .cmdsrc_regs = 0x0140, +- .names = { "U", "V", "W", "X" }, + }, + { + .val_regs = 0x01E0, +@@ -158,7 +192,6 @@ + .debounce_regs = 0x0190, + .tolerance_regs = 0x018c, + .cmdsrc_regs = 0x0170, +- .names = { "Y", "Z", "AA", "AB" }, + }, + { + .val_regs = 0x01e8, +@@ -167,7 +200,6 @@ + .debounce_regs = 0x01c0, + .tolerance_regs = 0x01bc, + .cmdsrc_regs = 0x01a0, +- .names = { "AC", "", "", "" }, + }, + }; + +@@ -187,6 +219,19 @@ + reg_cmdsrc1, + }; + ++struct aspeed_gpio_llops { ++ void (*reg_bit_set)(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg, bool val); ++ bool (*reg_bit_get)(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg); ++ int (*reg_bank_get)(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg); ++ void (*privilege_ctrl)(struct aspeed_gpio *gpio, unsigned int offset, int owner); ++ void (*privilege_init)(struct aspeed_gpio *gpio); ++ bool (*copro_request)(struct aspeed_gpio *gpio, unsigned int offset); ++ void (*copro_release)(struct aspeed_gpio *gpio, unsigned int offset); ++}; + + #define GPIO_VAL_VALUE 0x00 + #define GPIO_VAL_DIR 0x04 + +@@ -207,9 +252,9 @@ + #define GPIO_CMDSRC_RESERVED 3 + + /* This will be resolved at compile time */ +-static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, +- const struct aspeed_gpio_bank *bank, +- const enum aspeed_gpio_reg reg) ++static void __iomem *aspeed_gpio_g4_bank_reg(struct aspeed_gpio *gpio, ++ const struct aspeed_gpio_bank *bank, ++ const enum aspeed_gpio_reg reg) + { + switch (reg) { + case reg_val: +@@ -242,14 +287,43 @@ + BUG(); + } + ++static u32 aspeed_gpio_g7_reg_mask(const enum aspeed_gpio_reg reg) ++{ ++ switch (reg) { ++ case reg_val: ++ return GPIO_G7_CTRL_OUT_DATA; ++ case reg_dir: ++ return GPIO_G7_CTRL_DIR; ++ case reg_irq_enable: ++ return GPIO_G7_CTRL_IRQ_EN; ++ case reg_irq_type0: ++ return GPIO_G7_CTRL_IRQ_TYPE0; ++ case reg_irq_type1: ++ return GPIO_G7_CTRL_IRQ_TYPE1; ++ case reg_irq_type2: ++ return GPIO_G7_CTRL_IRQ_TYPE2; ++ case reg_tolerance: ++ return GPIO_G7_CTRL_RST_TOLERANCE; ++ case reg_debounce_sel1: ++ return GPIO_G7_CTRL_DEBOUNCE_SEL1; ++ case reg_debounce_sel2: ++ return GPIO_G7_CTRL_DEBOUNCE_SEL2; ++ case reg_rdata: ++ return GPIO_G7_CTRL_OUT_DATA; ++ case reg_irq_status: ++ return GPIO_G7_CTRL_IRQ_STS; ++ case reg_cmdsrc0: ++ case reg_cmdsrc1: + default: -+ priv->rst_crt = devm_reset_control_get_exclusive(&pdev->dev, NULL); -+ if (IS_ERR(priv->rst_crt)) { -+ dev_err(&pdev->dev, -+ "missing or invalid reset controller device tree entry"); -+ return PTR_ERR(priv->rst_crt); -+ } -+ reset_control_deassert(priv->rst_crt); -+ break; ++ WARN_ON_ONCE(1); ++ return 0; + } -+ -+ return 0; +} + - static int aspeed_gfx_load(struct drm_device *drm) + #define GPIO_BANK(x) ((x) >> 5) + #define GPIO_OFFSET(x) ((x) & 0x1f) + #define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + +-#define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o)) +-#define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1) +-#define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0) +- + static const struct aspeed_gpio_bank *to_bank(unsigned int offset) + { + unsigned int bank = GPIO_BANK(offset); +@@ -280,11 +354,11 @@ + static inline bool have_gpio(struct aspeed_gpio *gpio, unsigned int offset) + { + const struct aspeed_bank_props *props = find_bank_props(gpio, offset); +- const struct aspeed_gpio_bank *bank = to_bank(offset); +- unsigned int group = GPIO_OFFSET(offset) / 8; + +- return bank->names[group][0] != '\0' && +- (!props || ((props->input | props->output) & GPIO_BIT(offset))); ++ if (offset >= gpio->chip.ngpio) ++ return false; ++ ++ return (!props || ((props->input | props->output) & GPIO_BIT(offset))); + } + + static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset) +@@ -304,110 +378,49 @@ + return !props || (props->output & GPIO_BIT(offset)); + } + +-static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, +- const struct aspeed_gpio_bank *bank, +- int bindex, int cmdsrc) +-{ +- void __iomem *c0 = bank_reg(gpio, bank, reg_cmdsrc0); +- void __iomem *c1 = bank_reg(gpio, bank, reg_cmdsrc1); +- u32 bit, reg; +- +- /* +- * Each register controls 4 banks, so take the bottom 2 +- * bits of the bank index, and use them to select the +- * right control bit (0, 8, 16 or 24). +- */ +- bit = BIT((bindex & 3) << 3); +- +- /* Source 1 first to avoid illegal 11 combination */ +- reg = ioread32(c1); +- if (cmdsrc & 2) +- reg |= bit; +- else +- reg &= ~bit; +- iowrite32(reg, c1); +- +- /* Then Source 0 */ +- reg = ioread32(c0); +- if (cmdsrc & 1) +- reg |= bit; +- else +- reg &= ~bit; +- iowrite32(reg, c0); ++static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) ++{ ++ if (gpio->config->llops->privilege_ctrl) ++ gpio->config->llops->privilege_ctrl(gpio, offset, cmdsrc); + } + + static bool aspeed_gpio_copro_request(struct aspeed_gpio *gpio, + unsigned int offset) + { +- const struct aspeed_gpio_bank *bank = to_bank(offset); ++ if (gpio->config->llops->copro_request) ++ return gpio->config->llops->copro_request(gpio, offset); + +- if (!copro_ops || !gpio->cf_copro_bankmap) +- return false; +- if (!gpio->cf_copro_bankmap[offset >> 3]) +- return false; +- if (!copro_ops->request_access) +- return false; +- +- /* Pause the coprocessor */ +- copro_ops->request_access(copro_data); +- +- /* Change command source back to ARM */ +- aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, GPIO_CMDSRC_ARM); +- +- /* Update cache */ +- gpio->dcache[GPIO_BANK(offset)] = ioread32(bank_reg(gpio, bank, reg_rdata)); +- +- return true; ++ return false; + } + + static void aspeed_gpio_copro_release(struct aspeed_gpio *gpio, + unsigned int offset) + { +- const struct aspeed_gpio_bank *bank = to_bank(offset); +- +- if (!copro_ops || !gpio->cf_copro_bankmap) +- return; +- if (!gpio->cf_copro_bankmap[offset >> 3]) +- return; +- if (!copro_ops->release_access) +- return; +- +- /* Change command source back to ColdFire */ +- aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, +- GPIO_CMDSRC_COLDFIRE); ++ if (gpio->config->llops->copro_release) ++ gpio->config->llops->copro_release(gpio, offset); ++} + +- /* Restart the coprocessor */ +- copro_ops->release_access(copro_data); ++static bool aspeed_gpio_support_copro(struct aspeed_gpio *gpio) ++{ ++ return gpio->config->llops->copro_request && gpio->config->llops->copro_release && ++ gpio->config->llops->privilege_ctrl && gpio->config->llops->privilege_init; + } + + static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) { - struct platform_device *pdev = to_platform_device(drm->dev); -@@ -144,6 +388,7 @@ - struct device_node *np = pdev->dev.of_node; - const struct aspeed_gfx_config *config; - struct resource *res; -+ u64 dma_mask = 0; - int ret; + struct aspeed_gpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_gpio_bank *bank = to_bank(offset); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -160,13 +405,40 @@ - priv->vga_scratch_reg = config->vga_scratch_reg; - priv->throd_val = config->throd_val; - priv->scan_line_max = config->scan_line_max; -+ priv->flags = config->gfx_flags; -+ priv->pcie_int_reg = config->pcie_int_reg; -+ priv->pcie_int_mask = config->pcie_int_mask; -+ priv->pcie_int_l_to_h = config->pcie_int_l_to_h; -+ priv->pcie_int_h_to_l = config->pcie_int_h_to_l; -+ priv->pcie_link_reg = config->pcie_link_reg; -+ priv->pcie_link_bit = config->pcie_link_bit; -+ priv->soc_crt_bit = config->soc_crt_bit; -+ priv->soc_dp_bit = config->soc_dp_bit; -+ -+ /* Add pcie auto detect if the register has been assigned */ -+ if (priv->pcie_int_reg != 0x0) -+ priv->pcie_advance = 1; -+ else -+ priv->pcie_advance = 0; -+ -+ /* Set the DMA mask by addr */ -+ if (priv->flags & ADDR_64) -+ dma_mask = DMA_BIT_MASK(64); -+ else -+ dma_mask = DMA_BIT_MASK(32); +- return !!(ioread32(bank_reg(gpio, bank, reg_val)) & GPIO_BIT(offset)); ++ return gpio->config->llops->reg_bit_get(gpio, offset, reg_val); + } - priv->scu = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(priv->scu)) { -- priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu"); -+ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2400-scu"); - if (IS_ERR(priv->scu)) { -- dev_err(&pdev->dev, "failed to find SCU regmap\n"); -- return PTR_ERR(priv->scu); -+ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu"); -+ if (IS_ERR(priv->scu)) { -+ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2600-scu"); -+ if (IS_ERR(priv->scu)) { -+ dev_err(&pdev->dev, "failed to find SCU regmap\n"); -+ return PTR_ERR(priv->scu); -+ } -+ } - } - } + static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, + int val) + { + struct aspeed_gpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_gpio_bank *bank = to_bank(offset); +- void __iomem *addr; +- u32 reg; +- +- addr = bank_reg(gpio, bank, reg_val); +- reg = gpio->dcache[GPIO_BANK(offset)]; -@@ -177,19 +449,18 @@ - return ret; - } +- if (val) +- reg |= GPIO_BIT(offset); +- else +- reg &= ~GPIO_BIT(offset); +- gpio->dcache[GPIO_BANK(offset)] = reg; +- +- iowrite32(reg, addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_val, val); + /* Flush write */ +- ioread32(addr); ++ gpio->config->llops->reg_bit_get(gpio, offset, reg_val); + } -- ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32)); -+ ret = dma_set_mask_and_coherent(drm->dev, dma_mask); - if (ret) { - dev_err(&pdev->dev, "failed to set DMA mask: %d\n", ret); - return ret; - } + static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, +@@ -415,7 +428,7 @@ + { + struct aspeed_gpio *gpio = gpiochip_get_data(gc); + unsigned long flags; +- bool copro; ++ bool copro = false; -- priv->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); -- if (IS_ERR(priv->rst)) { -+ ret = aspeed_gfx_reset(drm); -+ if (ret) { - dev_err(&pdev->dev, - "missing or invalid reset controller device tree entry"); -- return PTR_ERR(priv->rst); -+ return ret; - } -- reset_control_deassert(priv->rst); + raw_spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); +@@ -430,22 +443,16 @@ + static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) + { + struct aspeed_gpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_gpio_bank *bank = to_bank(offset); +- void __iomem *addr = bank_reg(gpio, bank, reg_dir); + unsigned long flags; +- bool copro; +- u32 reg; ++ bool copro = false; - priv->clk = devm_clk_get(drm->dev, NULL); - if (IS_ERR(priv->clk)) { -@@ -199,6 +470,22 @@ - } - clk_prepare_enable(priv->clk); + if (!have_input(gpio, offset)) + return -ENOTSUPP; -+ if (priv->pcie_advance) { -+ ret = aspeed_pcie_active_detect(drm); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "missing or invalid pcie-ep controller device tree entry"); -+ return ret; -+ } -+ } -+ -+ ret = aspeed_adaptor_detect(drm); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "missing or invalid adaptor controller device tree entry"); -+ return ret; -+ } -+ - /* Sanitize control registers */ - writel(0, priv->base + CRT_CTRL1); - writel(0, priv->base + CRT_CTRL2); -@@ -232,6 +519,23 @@ - return ret; - } + raw_spin_lock_irqsave(&gpio->lock, flags); -+ /* install pcie reset detect */ -+ if (of_property_read_bool(np, "pcie-reset-detect") && priv->pcie_advance) { -+ dev_dbg(drm->dev, "hook pcie reset.\n"); -+ -+ /* Special watch the host power up / down */ -+ ret = devm_request_irq(drm->dev, platform_get_irq(pdev, 1), aspeed_host_irq_handler, IRQF_SHARED, "aspeed host active", drm); -+ if (ret < 0) { -+ dev_err(drm->dev, "Failed to install HOST active handler\n"); -+ return ret; -+ } -+ ret = devm_request_irq(drm->dev, platform_get_irq(pdev, 2), aspeed_host_irq_handler, IRQF_SHARED, "aspeed host deactivate", drm); -+ if (ret < 0) { -+ dev_err(drm->dev, "Failed to install HOST de-active handler\n"); -+ return ret; -+ } -+ } -+ - drm_mode_config_reset(drm); +- reg = ioread32(addr); +- reg &= ~GPIO_BIT(offset); +- + copro = aspeed_gpio_copro_request(gpio, offset); +- iowrite32(reg, addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 0); + if (copro) + aspeed_gpio_copro_release(gpio, offset); - return 0; -@@ -239,6 +543,12 @@ +@@ -458,23 +465,17 @@ + unsigned int offset, int val) + { + struct aspeed_gpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_gpio_bank *bank = to_bank(offset); +- void __iomem *addr = bank_reg(gpio, bank, reg_dir); + unsigned long flags; +- bool copro; +- u32 reg; ++ bool copro = false; - static void aspeed_gfx_unload(struct drm_device *drm) + if (!have_output(gpio, offset)) + return -ENOTSUPP; + + raw_spin_lock_irqsave(&gpio->lock, flags); + +- reg = ioread32(addr); +- reg |= GPIO_BIT(offset); +- + copro = aspeed_gpio_copro_request(gpio, offset); + __aspeed_gpio_set(gc, offset, val); +- iowrite32(reg, addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 1); + + if (copro) + aspeed_gpio_copro_release(gpio, offset); +@@ -486,7 +487,6 @@ + static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { -+ struct aspeed_gfx *priv = drm->dev_private; -+ -+ /* change the dp setting is coming from host side */ -+ if (priv->dp_support) -+ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, 0); -+ - drm_kms_helper_poll_fini(drm); - } + struct aspeed_gpio *gpio = gpiochip_get_data(gc); +- const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + u32 val; -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c ---- a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c 2025-12-23 10:16:20.973035200 +0000 -@@ -10,7 +10,19 @@ +@@ -498,7 +498,7 @@ - static int aspeed_gfx_get_modes(struct drm_connector *connector) + raw_spin_lock_irqsave(&gpio->lock, flags); + +- val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset); ++ val = gpio->config->llops->reg_bit_get(gpio, offset, reg_dir); + + raw_spin_unlock_irqrestore(&gpio->lock, flags); + +@@ -507,8 +507,7 @@ + + static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, + struct aspeed_gpio **gpio, +- const struct aspeed_gpio_bank **bank, +- u32 *bit, int *offset) ++ int *offset) { -- return drm_add_modes_noedid(connector, 800, 600); -+ struct aspeed_gfx *priv = container_of(connector, struct aspeed_gfx, connector); -+ int mode_count = 0; -+ -+ switch (priv->flags & CLK_MASK) { -+ case CLK_G6: -+ mode_count = drm_add_modes_noedid(connector, 1024, 768); -+ break; -+ default: -+ mode_count = drm_add_modes_noedid(connector, 800, 600); -+ break; -+ } -+ -+ return mode_count; + struct aspeed_gpio *internal; + +@@ -521,32 +520,25 @@ + return -ENOTSUPP; + + *gpio = internal; +- *bank = to_bank(*offset); +- *bit = GPIO_BIT(*offset); + + return 0; } - static const struct -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig ---- a/drivers/hwmon/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/hwmon/Kconfig 2025-12-23 10:16:08.059251693 +0000 -@@ -423,6 +423,16 @@ - This driver can also be built as a module. If so, the module - will be called aspeed_g6_pwm_tach. - -+config SENSORS_ASPEED_CHASSIS -+ tristate "ASPEED CHASSIS Driver" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ help -+ This driver provides support for Aspeed ast2600 chassis intruded -+ detect support. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called aspeed-chassis. -+ - config SENSORS_ATXP1 - tristate "Attansic ATXP1 VID controller" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile ---- a/drivers/hwmon/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/hwmon/Makefile 2025-12-23 10:16:11.821188606 +0000 -@@ -55,6 +55,7 @@ - obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o - obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o - obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tach.o -+obj-$(CONFIG_SENSORS_ASPEED_CHASSIS) += aspeed-chassis.o - obj-$(CONFIG_SENSORS_ASUS_ROG_RYUJIN) += asus_rog_ryujin.o - obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o - obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o -diff --git a/drivers/hwmon/aspeed-chassis.c b/drivers/hwmon/aspeed-chassis.c ---- a/drivers/hwmon/aspeed-chassis.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/hwmon/aspeed-chassis.c 2025-12-23 10:16:20.680040111 +0000 -@@ -0,0 +1,221 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2021 ASPEED Technology Inc. -+ * -+ * CHASSIS driver for the Aspeed SoC -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* #define USE_INTERRUPTS */ -+/******************************************************************************/ -+union chassis_ctrl_register { -+ u32 value; -+ struct { -+ uint32_t intrusion_status_clear : 1; /*[0]*/ -+ uint32_t intrusion_int_enable : 1; /*[1]*/ -+ uint32_t intrusion_status : 1; /*[2]*/ -+ uint32_t battery_power_good : 1; /*[3]*/ -+ uint32_t chassis_raw_status : 1; /*[4]*/ -+ uint32_t reserved0 : 3; /*[5-7]*/ -+ uint32_t io_power_status_clear : 1; /*[8]*/ -+ uint32_t io_power_int_enable : 1; /*[9]*/ -+ uint32_t core_power_status : 1; /*[10]*/ -+ uint32_t reserved1 : 5; /*[11-15]*/ -+ uint32_t core_power_status_clear : 1; /*[16]*/ -+ uint32_t core_power_int_enable : 1; /*[17]*/ -+ uint32_t io_power_status : 1; /*[18]*/ -+ uint32_t reserved2 : 13; /*[19-31]*/ -+ } fields; -+}; -+ -+struct aspeed_chassis { -+ struct device *dev; -+ void __iomem *base; -+ int irq; -+ /* for hwmon */ -+ const struct attribute_group *groups[2]; -+}; -+ -+static ssize_t -+intrusion_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ unsigned long val; -+ struct aspeed_chassis *chassis = dev_get_drvdata(dev); -+ union chassis_ctrl_register chassis_ctrl; -+ -+ if (kstrtoul(buf, 10, &val) < 0 || val != 0) -+ return -EINVAL; -+ -+ chassis_ctrl.value = readl(chassis->base); -+ chassis_ctrl.fields.intrusion_status_clear = 1; -+ writel(chassis_ctrl.value, chassis->base); -+ chassis_ctrl.fields.intrusion_status_clear = 0; -+ writel(chassis_ctrl.value, chassis->base); -+ return count; -+} -+ -+static ssize_t intrusion_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); -+ int index = sensor_attr->index; -+ struct aspeed_chassis *chassis = dev_get_drvdata(dev); -+ union chassis_ctrl_register chassis_ctrl; -+ u8 ret; -+ -+ chassis_ctrl.value = readl(chassis->base); -+ -+ switch (index) { -+ case 0: -+ ret = chassis_ctrl.fields.core_power_status; -+ break; -+ case 1: -+ ret = chassis_ctrl.fields.io_power_status; -+ break; -+ case 2: -+ ret = chassis_ctrl.fields.intrusion_status; -+ break; -+ } -+ -+ return sprintf(buf, "%d\n", ret); -+} -+ -+static SENSOR_DEVICE_ATTR_RO(core_power, intrusion, 0); -+static SENSOR_DEVICE_ATTR_RO(io_power, intrusion, 1); -+static SENSOR_DEVICE_ATTR_RW(intrusion0_alarm, intrusion, 2); -+ -+static struct attribute *intrusion_dev_attrs[] = { -+ &sensor_dev_attr_core_power.dev_attr.attr, -+ &sensor_dev_attr_io_power.dev_attr.attr, -+ &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, NULL -+}; -+ -+static const struct attribute_group intrusion_dev_group = { -+ .attrs = intrusion_dev_attrs, -+ .is_visible = NULL, -+}; -+ -+#ifdef USE_INTERRUPTS -+static void aspeed_chassis_status_check(struct aspeed_chassis *chassis) -+{ -+ union chassis_ctrl_register chassis_ctrl; -+ -+ chassis_ctrl.value = readl(chassis->base); -+ if (chassis_ctrl.fields.intrusion_status) { -+ dev_info(chassis->dev, "CHASI# pin has been pulled low"); -+ chassis_ctrl.fields.intrusion_status_clear = 1; -+ writel(chassis_ctrl.value, chassis->base); -+ chassis_ctrl.fields.intrusion_status_clear = 0; -+ writel(chassis_ctrl.value, chassis->base); -+ } -+ -+ if (chassis_ctrl.fields.core_power_status) { -+ dev_info(chassis->dev, "Core power has been pulled low"); -+ chassis_ctrl.fields.core_power_status_clear = 1; -+ writel(chassis_ctrl.value, chassis->base); -+ chassis_ctrl.fields.core_power_status_clear = 0; -+ writel(chassis_ctrl.value, chassis->base); -+ } -+ -+ if (chassis_ctrl.fields.io_power_status) { -+ dev_info(chassis->dev, "IO power has been pulled low"); -+ chassis_ctrl.fields.io_power_status_clear = 1; -+ writel(chassis_ctrl.value, chassis->base); -+ chassis_ctrl.fields.io_power_status_clear = 0; -+ writel(chassis_ctrl.value, chassis->base); -+ } -+} -+ -+static irqreturn_t aspeed_chassis_isr(int this_irq, void *dev_id) -+{ -+ struct aspeed_chassis *chassis = dev_id; -+ -+ aspeed_chassis_status_check(chassis); -+ return IRQ_HANDLED; -+} -+#endif -+ -+static void aspeed_chassis_int_ctrl(struct aspeed_chassis *chassis, bool ctrl) -+{ -+ union chassis_ctrl_register chassis_ctrl; -+ -+ chassis_ctrl.value = readl(chassis->base); -+ chassis_ctrl.fields.intrusion_int_enable = ctrl; -+ chassis_ctrl.fields.io_power_int_enable = ctrl; -+ chassis_ctrl.fields.core_power_int_enable = ctrl; -+ writel(chassis_ctrl.value, chassis->base); -+} -+ -+static const struct of_device_id aspeed_chassis_of_table[] = { -+ { .compatible = "aspeed,ast2600-chassis" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_chassis_of_table); -+ -+static int aspeed_chassis_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct aspeed_chassis *priv; -+ struct device *hwmon; -+ int __maybe_unused ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->dev = dev; -+ priv->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->base)) -+ return PTR_ERR(priv->base); -+#ifdef USE_INTERRUPTS -+ priv->irq = platform_get_irq(pdev, 0); -+ if (priv->irq < 0) { -+ dev_err(dev, "no irq specified\n"); -+ return -ENOENT; -+ } -+ -+ ret = devm_request_irq(dev, priv->irq, aspeed_chassis_isr, 0, -+ dev_name(dev), priv); -+ if (ret) { -+ dev_err(dev, "Chassis Unable to get IRQ"); -+ return ret; -+ } -+ aspeed_chassis_int_ctrl(priv, true); -+#else -+ aspeed_chassis_int_ctrl(priv, false); -+#endif -+ -+ priv->groups[0] = &intrusion_dev_group; -+ priv->groups[1] = NULL; -+ -+ hwmon = devm_hwmon_device_register_with_groups(dev, "aspeed_chassis", -+ priv, priv->groups); -+ -+ return PTR_ERR_OR_ZERO(hwmon); -+} -+ -+static struct platform_driver aspeed_chassis_driver = { -+ .probe = aspeed_chassis_probe, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_chassis_of_table, -+ }, -+}; -+ -+module_platform_driver(aspeed_chassis_driver); -+ -+MODULE_AUTHOR("Billy Tsai"); -+MODULE_DESCRIPTION("ASPEED CHASSIS Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c ---- a/drivers/hwmon/aspeed-g6-pwm-tach.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/hwmon/aspeed-g6-pwm-tach.c 2025-12-23 10:16:20.686040010 +0000 -@@ -56,6 +56,7 @@ - #include - #include - #include -+#include - #include - #include + static void aspeed_gpio_irq_ack(struct irq_data *d) + { +- const struct aspeed_gpio_bank *bank; + struct aspeed_gpio *gpio; + unsigned long flags; +- void __iomem *status_addr; + int rc, offset; +- bool copro; +- u32 bit; ++ bool copro = false; -@@ -137,7 +138,7 @@ - struct reset_control *reset; - unsigned long clk_rate; - bool tach_present[TACH_ASPEED_NR_TACHS]; -- u32 tach_divisor; -+ u32 tach_divisor[TACH_ASPEED_NR_TACHS]; - }; +- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); ++ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); + if (rc) + return; + +- status_addr = bank_reg(gpio, bank, reg_irq_status); +- + raw_spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); - static inline struct aspeed_pwm_tach_data * -@@ -282,12 +283,14 @@ - priv->base + TACH_ASPEED_CTRL(tach_ch)); - } +- iowrite32(bit, status_addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); --static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, u32 tach_val) -+static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, -+ u32 tach_val, u8 fan_tach_ch) + if (copro) + aspeed_gpio_copro_release(gpio, offset); +@@ -555,20 +547,15 @@ + + static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) { - u64 rpm; - u32 tach_div; +- const struct aspeed_gpio_bank *bank; + struct aspeed_gpio *gpio; + unsigned long flags; +- u32 reg, bit; +- void __iomem *addr; + int rc, offset; +- bool copro; ++ bool copro = false; -- tach_div = tach_val * priv->tach_divisor * DEFAULT_FAN_PULSE_PR; -+ tach_div = tach_val * priv->tach_divisor[fan_tach_ch] * -+ DEFAULT_FAN_PULSE_PR; +- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); ++ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); + if (rc) + return; - dev_dbg(priv->dev, "clk %ld, tach_val %d , tach_div %d\n", - priv->clk_rate, tach_val, tach_div); -@@ -308,7 +311,7 @@ - if (!(val & TACH_ASPEED_FULL_MEASUREMENT)) - return 0; - val = FIELD_GET(TACH_ASPEED_VALUE_MASK, val); -- return aspeed_tach_val_to_rpm(priv, val); -+ return aspeed_tach_val_to_rpm(priv, val, fan_tach_ch); - } +- addr = bank_reg(gpio, bank, reg_irq_enable); +- + /* Unmasking the IRQ */ + if (set) + gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); +@@ -576,12 +563,7 @@ + raw_spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); - static int aspeed_tach_hwmon_read(struct device *dev, -@@ -345,11 +348,11 @@ - if (!is_power_of_2(val) || (ilog2(val) % 2) || - DIV_TO_REG(val) > 0xb) - return -EINVAL; -- priv->tach_divisor = val; -+ priv->tach_divisor[channel] = val; - reg_val = readl(priv->base + TACH_ASPEED_CTRL(channel)); - reg_val &= ~TACH_ASPEED_CLK_DIV_T_MASK; - reg_val |= FIELD_PREP(TACH_ASPEED_CLK_DIV_T_MASK, -- DIV_TO_REG(priv->tach_divisor)); -+ DIV_TO_REG(priv->tach_divisor[channel])); - writel(reg_val, priv->base + TACH_ASPEED_CTRL(channel)); +- reg = ioread32(addr); +- if (set) +- reg |= bit; +- else +- reg &= ~bit; +- iowrite32(reg, addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_enable, set); + + if (copro) + aspeed_gpio_copro_release(gpio, offset); +@@ -607,34 +589,31 @@ + u32 type0 = 0; + u32 type1 = 0; + u32 type2 = 0; +- u32 bit, reg; +- const struct aspeed_gpio_bank *bank; + irq_flow_handler_t handler; + struct aspeed_gpio *gpio; + unsigned long flags; +- void __iomem *addr; + int rc, offset; +- bool copro; ++ bool copro = false; + +- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); ++ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); + if (rc) + return -EINVAL; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: +- type2 |= bit; ++ type2 = 1; + fallthrough; + case IRQ_TYPE_EDGE_RISING: +- type0 |= bit; ++ type0 = 1; + fallthrough; + case IRQ_TYPE_EDGE_FALLING: + handler = handle_edge_irq; + break; + case IRQ_TYPE_LEVEL_HIGH: +- type0 |= bit; ++ type0 = 1; + fallthrough; + case IRQ_TYPE_LEVEL_LOW: +- type1 |= bit; ++ type1 = 1; + handler = handle_level_irq; break; default: -@@ -407,7 +410,7 @@ - for (index = 0; index < count; index++) { - ch = tach_ch[index]; - priv->tach_present[ch] = true; -- priv->tach_divisor = DEFAULT_TACH_DIV; -+ priv->tach_divisor[ch] = DEFAULT_TACH_DIV; +@@ -644,20 +623,9 @@ + raw_spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); - val = readl(priv->base + TACH_ASPEED_CTRL(ch)); - val &= ~(TACH_ASPEED_INVERS_LIMIT | TACH_ASPEED_DEBOUNCE_MASK | -@@ -416,7 +419,7 @@ - val |= (DEBOUNCE_3_CLK << TACH_ASPEED_DEBOUNCE_BIT) | - F2F_EDGES | - FIELD_PREP(TACH_ASPEED_CLK_DIV_T_MASK, -- DIV_TO_REG(priv->tach_divisor)); -+ DIV_TO_REG(priv->tach_divisor[ch])); - writel(val, priv->base + TACH_ASPEED_CTRL(ch)); +- addr = bank_reg(gpio, bank, reg_irq_type0); +- reg = ioread32(addr); +- reg = (reg & ~bit) | type0; +- iowrite32(reg, addr); +- +- addr = bank_reg(gpio, bank, reg_irq_type1); +- reg = ioread32(addr); +- reg = (reg & ~bit) | type1; +- iowrite32(reg, addr); +- +- addr = bank_reg(gpio, bank, reg_irq_type2); +- reg = ioread32(addr); +- reg = (reg & ~bit) | type2; +- iowrite32(reg, addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); - aspeed_tach_ch_enable(priv, ch, true); -@@ -452,6 +455,50 @@ - reset_control_assert(rst); - } + if (copro) + aspeed_gpio_copro_release(gpio, offset); +@@ -672,7 +640,6 @@ + { + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); +- struct aspeed_gpio *data = gpiochip_get_data(gc); + unsigned int i, p, banks; + unsigned long reg; + struct aspeed_gpio *gpio = gpiochip_get_data(gc); +@@ -681,9 +648,7 @@ -+static void aspeed_pwm_set_wdt_reload(struct pwm_chip *chip, -+ struct pwm_device *pwm, -+ u64 reload_duty_cycle) -+{ -+ struct aspeed_pwm_tach_data *priv = aspeed_pwm_chip_to_data(chip); -+ u32 hwpwm = pwm->hwpwm, val; -+ -+ val = readl(priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); -+ val &= ~PWM_ASPEED_DUTY_CYCLE_POINT_AS_WDT; -+ val |= FIELD_PREP(PWM_ASPEED_DUTY_CYCLE_POINT_AS_WDT, -+ reload_duty_cycle); -+ writel(val, priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); -+ -+ val = readl(priv->base + PWM_ASPEED_CTRL(hwpwm)); -+ val |= PWM_ASPEED_CTRL_DUTY_LOAD_AS_WDT_ENABLE; -+ writel(val, priv->base + PWM_ASPEED_CTRL(hwpwm)); -+} -+ -+static struct pwm_device * -+aspeed_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) -+{ -+ struct pwm_device *pwm; -+ -+ /* period in the second cell and flags in the third cell are optional */ -+ if (args->args_count < 1) -+ return ERR_PTR(-EINVAL); -+ -+ pwm = pwm_request_from_chip(chip, args->args[0], NULL); -+ if (IS_ERR(pwm)) -+ return pwm; -+ -+ if (args->args_count > 1) -+ pwm->args.period = args->args[1]; -+ -+ pwm->args.polarity = PWM_POLARITY_NORMAL; -+ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) -+ pwm->args.polarity = PWM_POLARITY_INVERSED; -+ -+ if (args->args_count > 3 && args->args[3] < U8_MAX) -+ aspeed_pwm_set_wdt_reload(chip, pwm, args->args[3]); -+ -+ return pwm; -+} -+ - static int aspeed_pwm_tach_probe(struct platform_device *pdev) + banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); + for (i = 0; i < banks; i++) { +- const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; +- +- reg = ioread32(bank_reg(data, bank, reg_irq_status)); ++ reg = gpio->config->llops->reg_bank_get(gpio, i * 32, reg_irq_status); + + for_each_set_bit(p, ®, 32) + generic_handle_domain_irq(gc->irq.domain, i * 32 + p); +@@ -722,23 +687,12 @@ { - struct device *dev = &pdev->dev, *hwmon; -@@ -493,6 +540,8 @@ - pwmchip_set_drvdata(chip, priv); - chip->ops = &aspeed_pwm_ops; + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + unsigned long flags; +- void __iomem *treg; +- bool copro; +- u32 val; +- +- treg = bank_reg(gpio, to_bank(offset), reg_tolerance); ++ bool copro = false; -+ chip->of_xlate = aspeed_pwm_xlate; -+ - ret = devm_pwmchip_add(dev, chip); - if (ret) - return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); -@@ -528,6 +577,9 @@ - { - .compatible = "aspeed,ast2600-pwm-tach", - }, -+ { -+ .compatible = "aspeed,ast2700-pwm-tach", -+ }, - {}, - }; - MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); -diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig ---- a/drivers/i2c/busses/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/i2c/busses/Kconfig 2025-12-23 10:16:07.612259189 +0000 -@@ -411,6 +411,17 @@ - This driver can also be built as a module. If so, the module - will be called i2c-altera. - -+config I2C_AST2600 -+ tristate "Aspeed I2C v2 Controller" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ select I2C_SMBUS -+ help -+ If you say yes to this option, support will be included for the -+ Aspeed I2C controller with new register set. -+ -+ This driver can also be built as a module. If so, the module -+ will be called i2c-ast2600. -+ - config I2C_ASPEED - tristate "Aspeed I2C Controller" - depends on ARCH_ASPEED || COMPILE_TEST -diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile ---- a/drivers/i2c/busses/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/i2c/busses/Makefile 2025-12-23 10:16:11.163199640 +0000 -@@ -39,6 +39,7 @@ - obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o - obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o - obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o -+obj-$(CONFIG_I2C_AST2600) += i2c-ast2600.o - obj-$(CONFIG_I2C_AT91) += i2c-at91.o - i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o - ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y) -diff --git a/drivers/i2c/busses/i2c-ast2600.c b/drivers/i2c/busses/i2c-ast2600.c ---- a/drivers/i2c/busses/i2c-ast2600.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i2c/busses/i2c-ast2600.c 2025-12-23 10:16:20.640040781 +0000 -@@ -0,0 +1,2421 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * ASPEED AST2600 new register set I2C controller driver -+ * -+ * Copyright (C) ASPEED Technology Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define AST2600_I2CG_ISR 0x00 -+#define AST2600_I2CG_SLAVE_ISR 0x04 -+#define AST2600_I2CG_OWNER 0x08 -+#define AST2600_I2CG_CTRL 0x0C -+#define AST2600_I2CG_CLK_DIV_CTRL 0x10 -+ -+#define AST2600_I2CG_SLAVE_PKT_NAK BIT(4) -+#define AST2600_I2CG_M_S_SEPARATE_INTR BIT(3) -+#define AST2600_I2CG_CTRL_NEW_REG BIT(2) -+#define AST2600_I2CG_CTRL_NEW_CLK_DIV BIT(1) -+#define AST2600_GLOBAL_INIT \ -+ (AST2600_I2CG_CTRL_NEW_REG | AST2600_I2CG_CTRL_NEW_CLK_DIV) -+/* -+ * APB clk : 100Mhz -+ * div : scl : baseclk [APB/((div/2) + 1)] : tBuf [1/bclk * 16] -+ * I2CG10[31:24] base clk4 for i2c auto recovery timeout counter (0xC6) -+ * I2CG10[23:16] base clk3 for Standard-mode (100Khz) min tBuf 4.7us -+ * 0x3c : 100.8Khz : 3.225Mhz : 4.96us -+ * 0x3d : 99.2Khz : 3.174Mhz : 5.04us -+ * 0x3e : 97.65Khz : 3.125Mhz : 5.12us -+ * 0x40 : 97.75Khz : 3.03Mhz : 5.28us -+ * 0x41 : 99.5Khz : 2.98Mhz : 5.36us (default) -+ * I2CG10[15:8] base clk2 for Fast-mode (400Khz) min tBuf 1.3us -+ * 0x12 : 400Khz : 10Mhz : 1.6us -+ * I2CG10[7:0] base clk1 for Fast-mode Plus (1Mhz) min tBuf 0.5us -+ * 0x08 : 1Mhz : 20Mhz : 0.8us -+ */ -+#define AST2600_I2CCG_DIV_CTRL 0xC6411208 -+#define AST2700_I2CCG_DIV_CTRL 0xC6220904 -+#define AST2700_MIN_AC_TIMING 12000 -+ -+/* 0x00 : I2CC Controller/Target Function Control Register */ -+#define AST2600_I2CC_FUN_CTRL 0x00 -+#define AST2600_I2CC_SLAVE_ADDR_RX_EN BIT(20) -+#define AST2600_I2CC_MASTER_RETRY_MASK GENMASK(19, 18) -+#define AST2600_I2CC_MASTER_RETRY(x) (((x) & GENMASK(1, 0)) << 18) -+#define AST2600_I2CC_BUS_AUTO_RELEASE BIT(17) -+#define AST2600_I2CC_M_SDA_LOCK_EN BIT(16) -+#define AST2600_I2CC_MULTI_MASTER_DIS BIT(15) -+#define AST2600_I2CC_M_SCL_DRIVE_EN BIT(14) -+#define AST2600_I2CC_MSB_STS BIT(9) -+#define AST2600_I2CC_SDA_DRIVE_1T_EN BIT(8) -+#define AST2600_I2CC_M_SDA_DRIVE_1T_EN BIT(7) -+#define AST2600_I2CC_M_HIGH_SPEED_EN BIT(6) -+#define AST2700_I2CC_MANUAL_DEBOUNCE GENMASK(5, 4) -+/* reserver 5 : 2 */ -+#define AST2600_I2CC_SLAVE_EN BIT(1) -+#define AST2600_I2CC_MASTER_EN BIT(0) -+ -+/* 0x04 : I2CC Controller/Target Clock and AC Timing Control Register #1 */ -+#define AST2600_I2CC_AC_TIMING 0x04 -+#define AST2600_I2CC_TTIMEOUT(x) (((x) & GENMASK(4, 0)) << 24) -+#define AST2700_I2CC_TTIMEOUT(x) (((x) & GENMASK(5, 0)) << 24) -+#define AST2600_I2CC_TCKHIGHMIN(x) (((x) & GENMASK(3, 0)) << 20) -+#define AST2600_I2CC_TCKHIGH(x) (((x) & GENMASK(3, 0)) << 16) -+#define AST2600_I2CC_TCKLOW(x) (((x) & GENMASK(3, 0)) << 12) -+#define AST2600_I2CC_THDDAT(x) (((x) & GENMASK(1, 0)) << 10) -+#define AST2600_I2CC_TOUTBASECLK(x) (((x) & GENMASK(1, 0)) << 8) -+#define AST2600_I2CC_TBASECLK(x) ((x) & GENMASK(3, 0)) -+#define AST2600_I2CC_AC_TIMING_MASK GENMASK(23, 0) -+ -+/* 0x08 : I2CC Controller/Target Transmit/Receive Byte Buffer Register */ -+#define AST2600_I2CC_STS_AND_BUFF 0x08 -+#define AST2600_I2CC_TX_DIR_MASK GENMASK(31, 29) -+#define AST2600_I2CC_SDA_OE BIT(28) -+#define AST2600_I2CC_SDA_O BIT(27) -+#define AST2600_I2CC_SCL_OE BIT(26) -+#define AST2600_I2CC_SCL_O BIT(25) -+ -+#define AST2600_I2CC_SCL_LINE_STS BIT(18) -+#define AST2600_I2CC_SDA_LINE_STS BIT(17) -+#define AST2600_I2CC_BUS_BUSY_STS BIT(16) -+ -+#define AST2600_I2CC_GET_RX_BUFF(x) (((x) >> 8) & GENMASK(7, 0)) -+ -+/* 0x0C : I2CC Controller/Target Pool Buffer Control Register */ -+#define AST2600_I2CC_BUFF_CTRL 0x0C -+#define AST2600_I2CC_GET_RX_BUF_LEN(x) (((x) & GENMASK(29, 24)) >> 24) -+#define AST2600_I2CC_SET_RX_BUF_LEN(x) (((((x) - 1) & GENMASK(4, 0)) << 16) | BIT(0)) -+#define AST2600_I2CC_SET_TX_BUF_LEN(x) (((((x) - 1) & GENMASK(4, 0)) << 8) | BIT(0)) -+#define AST2600_I2CC_GET_TX_BUF_LEN(x) ((((x) & GENMASK(12, 8)) >> 8) + 1) -+ -+/* 0x10 : I2CM Controller Interrupt Control Register */ -+#define AST2600_I2CM_IER 0x10 -+/* 0x14 : I2CM Controller Interrupt Status Register : WC */ -+#define AST2600_I2CM_ISR 0x14 -+ -+#define AST2600_I2CM_ISR_MASK GENMASK(31, 21) -+#define AST2600_I2CM_SW_ISR_MASK GENMASK(31, 19) -+ -+#define AST2600_I2CM_PKT_TIMEOUT BIT(18) -+#define AST2600_I2CM_PKT_ERROR BIT(17) -+#define AST2600_I2CM_PKT_DONE BIT(16) -+ -+#define AST2600_I2CM_BUS_RECOVER_FAIL BIT(15) -+#define AST2600_I2CM_SDA_DL_TO BIT(14) -+#define AST2600_I2CM_BUS_RECOVER BIT(13) -+#define AST2600_I2CM_SMBUS_ALT BIT(12) -+#define AST2700_I2CM_ABNORMAL_ACTION BIT(8) -+ -+#define AST2600_I2CM_SCL_LOW_TO BIT(6) -+#define AST2600_I2CM_ABNORMAL BIT(5) -+#define AST2600_I2CM_NORMAL_STOP BIT(4) -+#define AST2600_I2CM_ARBIT_LOSS BIT(3) -+#define AST2600_I2CM_RX_DONE BIT(2) -+#define AST2600_I2CM_TX_NAK BIT(1) -+#define AST2600_I2CM_TX_ACK BIT(0) -+ -+/* 0x18 : I2CM Controller Command/Status Register */ -+#define AST2600_I2CM_CMD_STS 0x18 -+#define AST2600_I2CM_PKT_ADDR(x) (((x) & GENMASK(6, 0)) << 24) -+#define AST2600_I2CM_PKT_EN BIT(16) -+#define AST2600_I2CM_SDA_OE_OUT_DIR BIT(15) -+#define AST2600_I2CM_SDA_O_OUT_DIR BIT(14) -+#define AST2600_I2CM_SCL_OE_OUT_DIR BIT(13) -+#define AST2600_I2CM_SCL_O_OUT_DIR BIT(12) -+#define AST2600_I2CM_RECOVER_CMD_EN BIT(11) -+ -+#define AST2600_I2CM_RX_DMA_EN BIT(9) -+#define AST2600_I2CM_TX_DMA_EN BIT(8) -+/* Command Bit */ -+#define AST2600_I2CM_RX_BUFF_EN BIT(7) -+#define AST2600_I2CM_TX_BUFF_EN BIT(6) -+#define AST2600_I2CM_STOP_CMD BIT(5) -+#define AST2600_I2CM_RX_CMD_LAST BIT(4) -+#define AST2600_I2CM_RX_CMD BIT(3) -+ -+#define AST2600_I2CM_TX_CMD BIT(1) -+#define AST2600_I2CM_START_CMD BIT(0) + raw_spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); + +- val = readl(treg); +- +- if (enable) +- val |= GPIO_BIT(offset); +- else +- val &= ~GPIO_BIT(offset); +- +- writel(val, treg); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); + + if (copro) + aspeed_gpio_copro_release(gpio, offset); +@@ -832,21 +786,11 @@ + static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, + unsigned int timer) + { +- const struct aspeed_gpio_bank *bank = to_bank(offset); +- const u32 mask = GPIO_BIT(offset); +- void __iomem *addr; +- u32 val; +- + /* Note: Debounce timer isn't under control of the command + * source registers, so no need to sync with the coprocessor + */ +- addr = bank_reg(gpio, bank, reg_debounce_sel1); +- val = ioread32(addr); +- iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); +- +- addr = bank_reg(gpio, bank, reg_debounce_sel2); +- val = ioread32(addr); +- iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_debounce_sel1, !!(timer & BIT(1))); ++ gpio->config->llops->reg_bit_set(gpio, offset, reg_debounce_sel2, !!(timer & BIT(0))); + } + + static int enable_debounce(struct gpio_chip *chip, unsigned int offset, +@@ -877,15 +821,15 @@ + } + + /* Try to find a timer already configured for the debounce period */ +- for (i = 1; i < ARRAY_SIZE(debounce_timers); i++) { ++ for (i = 1; i < gpio->config->debounce_timers_num; i++) { + u32 cycles; + +- cycles = ioread32(gpio->base + debounce_timers[i]); ++ cycles = ioread32(gpio->base + gpio->config->debounce_timers_array[i]); + if (requested_cycles == cycles) + break; + } + +- if (i == ARRAY_SIZE(debounce_timers)) { ++ if (i == gpio->config->debounce_timers_num) { + int j; + + /* +@@ -899,8 +843,8 @@ + + if (j == ARRAY_SIZE(gpio->timer_users)) { + dev_warn(chip->parent, +- "Debounce timers exhausted, cannot debounce for period %luus\n", +- usecs); ++ "Debounce timers exhausted, cannot debounce for period %luus\n", ++ usecs); + + rc = -EPERM; + +@@ -916,7 +860,7 @@ + + i = j; + +- iowrite32(requested_cycles, gpio->base + debounce_timers[i]); ++ iowrite32(requested_cycles, gpio->base + gpio->config->debounce_timers_array[i]); + } + + if (WARN(i == 0, "Cannot register index of disabled timer\n")) { +@@ -1019,6 +963,9 @@ + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + ++ if (!aspeed_gpio_support_copro(gpio)) ++ return -EOPNOTSUPP; + -+/* 0x1C : I2CM Controller DMA Transfer Length Register */ -+#define AST2600_I2CM_DMA_LEN 0x1C -+/* Controller Tx Rx support length 1 ~ 4096 */ -+#define AST2600_I2CM_SET_RX_DMA_LEN(x) ((((x) & GENMASK(11, 0)) << 16) | BIT(31)) -+#define AST2600_I2CM_SET_TX_DMA_LEN(x) (((x) & GENMASK(11, 0)) | BIT(15)) + if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL); + if (!gpio->cf_copro_bankmap) +@@ -1038,7 +985,7 @@ + + /* Switch command source */ + if (gpio->cf_copro_bankmap[bindex] == 1) +- aspeed_gpio_change_cmd_source(gpio, bank, bindex, ++ aspeed_gpio_change_cmd_source(gpio, offset, + GPIO_CMDSRC_COLDFIRE); + + if (vreg_offset) +@@ -1062,9 +1009,11 @@ + struct gpio_chip *chip = gpiod_to_chip(desc); + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); +- const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + ++ if (!aspeed_gpio_support_copro(gpio)) ++ return -EOPNOTSUPP; + -+/* 0x20 : I2CS Target Interrupt Control Register */ -+#define AST2600_I2CS_IER 0x20 -+/* 0x24 : I2CS Target Interrupt Status Register */ -+#define AST2600_I2CS_ISR 0x24 + if (!gpio->cf_copro_bankmap) + return -ENXIO; + +@@ -1083,7 +1032,7 @@ + + /* Switch command source */ + if (gpio->cf_copro_bankmap[bindex] == 0) +- aspeed_gpio_change_cmd_source(gpio, bank, bindex, ++ aspeed_gpio_change_cmd_source(gpio, offset, + GPIO_CMDSRC_ARM); + bail: + raw_spin_unlock_irqrestore(&gpio->lock, flags); +@@ -1093,12 +1042,10 @@ + + static void aspeed_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) + { +- const struct aspeed_gpio_bank *bank; + struct aspeed_gpio *gpio; +- u32 bit; + int rc, offset; + +- rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); ++ rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); + if (rc) + return; + +@@ -1115,6 +1062,173 @@ + GPIOCHIP_IRQ_RESOURCE_HELPERS, + }; + ++static void aspeed_g4_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg, bool val) ++{ ++ const struct aspeed_gpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); ++ u32 temp; + -+#define AST2600_I2CS_ADDR_INDICATE_MASK GENMASK(31, 30) -+#define AST2600_I2CS_SLAVE_PENDING BIT(29) -+#define AST2600_I2CS_SADDR_PENDING BIT(28) ++ if (reg == reg_val) ++ temp = gpio->dcache[GPIO_BANK(offset)]; ++ else ++ temp = ioread32(addr); + -+#define AST2600_I2CS_WAIT_TX_DMA BIT(25) -+#define AST2600_I2CS_WAIT_RX_DMA BIT(24) ++ if (val) ++ temp |= GPIO_BIT(offset); ++ else ++ temp &= ~GPIO_BIT(offset); + -+#define AST2600_I2CS_ADDR3_NAK BIT(22) -+#define AST2600_I2CS_ADDR2_NAK BIT(21) -+#define AST2600_I2CS_ADDR1_NAK BIT(20) ++ if (reg == reg_val) ++ gpio->dcache[GPIO_BANK(offset)] = temp; ++ iowrite32(temp, addr); ++} + -+#define AST2600_I2CS_ADDR_NAK_MASK GENMASK(22, 20) -+#define AST2600_I2CS_ADDR_MASK GENMASK(19, 18) -+#define AST2600_I2CS_GET_TARGET(x) (((x) >> 30) & 0x3) -+#define AST2600_I2CS_PKT_ERROR BIT(17) -+#define AST2600_I2CS_PKT_DONE BIT(16) -+#define AST2600_I2CS_INACTIVE_TO BIT(15) ++static bool aspeed_g4_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) ++{ ++ const struct aspeed_gpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + -+#define AST2600_I2CS_SLAVE_MATCH BIT(7) -+#define AST2600_I2CS_ABNOR_STOP BIT(5) -+#define AST2600_I2CS_STOP BIT(4) -+#define AST2600_I2CS_RX_DONE_NAK BIT(3) -+#define AST2600_I2CS_RX_DONE BIT(2) -+#define AST2600_I2CS_TX_NAK BIT(1) -+#define AST2600_I2CS_TX_ACK BIT(0) ++ return !!(ioread32(addr) & GPIO_BIT(offset)); ++} + -+/* 0x28 : I2CS Target CMD/Status Register */ -+#define AST2600_I2CS_CMD_STS 0x28 -+#define AST2600_I2CS_ACTIVE_ALL GENMASK(18, 17) -+#define AST2600_I2CS_PKT_MODE_EN BIT(16) -+#define AST2600_I2CS_AUTO_NAK_NOADDR BIT(15) -+#define AST2600_I2CS_AUTO_NAK_EN BIT(14) ++static int aspeed_g4_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) ++{ ++ const struct aspeed_gpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + -+#define AST2600_I2CS_ALT_EN BIT(10) -+#define AST2600_I2CS_RX_DMA_EN BIT(9) -+#define AST2600_I2CS_TX_DMA_EN BIT(8) -+#define AST2600_I2CS_RX_BUFF_EN BIT(7) -+#define AST2600_I2CS_TX_BUFF_EN BIT(6) -+#define AST2600_I2CS_RX_CMD_LAST BIT(4) ++ if (reg == reg_rdata || reg == reg_irq_status) ++ return ioread32(addr); ++ else ++ return -EOPNOTSUPP; ++} + -+#define AST2600_I2CS_TX_CMD BIT(2) ++static void aspeed_g4_privilege_ctrl(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) ++{ ++ /* ++ * The command source register is only valid in bits 0, 8, 16, and 24, so we use ++ * (offset & ~(0x7)) to ensure that reg_bits_set always targets a valid bit. ++ */ ++ /* Source 1 first to avoid illegal 11 combination */ ++ aspeed_g4_reg_bit_set(gpio, offset & ~(0x7), reg_cmdsrc1, !!(cmdsrc & BIT(1))); ++ /* Then Source 0 */ ++ aspeed_g4_reg_bit_set(gpio, offset & ~(0x7), reg_cmdsrc0, !!(cmdsrc & BIT(0))); ++} + -+#define AST2600_I2CS_DMA_LEN 0x2C ++static void aspeed_g4_privilege_init(struct aspeed_gpio *gpio) ++{ ++ u32 i; + -+/* Target Tx Rx support length 1 ~ 4096 */ -+#define AST2600_I2CS_SET_RX_DMA_LEN(x) (((((x) - 1) & GENMASK(11, 0)) << 16) | BIT(31)) -+#define AST2600_I2CS_SET_TX_DMA_LEN(x) ((((x) - 1) & GENMASK(11, 0)) | BIT(15)) ++ /* Switch all command sources to the ARM by default */ ++ for (i = 0; i < DIV_ROUND_UP(gpio->chip.ngpio, 32); i++) { ++ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 0, GPIO_CMDSRC_ARM); ++ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 8, GPIO_CMDSRC_ARM); ++ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 16, GPIO_CMDSRC_ARM); ++ aspeed_g4_privilege_ctrl(gpio, (i << 5) + 24, GPIO_CMDSRC_ARM); ++ } ++} + -+/* I2CM Controller DMA Tx Buffer Register */ -+#define AST2600_I2CM_TX_DMA 0x30 -+/* I2CM Controller DMA Rx Buffer Register */ -+#define AST2600_I2CM_RX_DMA 0x34 -+/* I2CS Target DMA Tx Buffer Register */ -+#define AST2600_I2CS_TX_DMA 0x38 -+/* I2CS Target DMA Rx Buffer Register */ -+#define AST2600_I2CS_RX_DMA 0x3C ++static bool aspeed_g4_copro_request(struct aspeed_gpio *gpio, unsigned int offset) ++{ ++ if (!copro_ops || !gpio->cf_copro_bankmap) ++ return false; ++ if (!gpio->cf_copro_bankmap[offset >> 3]) ++ return false; ++ if (!copro_ops->request_access) ++ return false; + -+/* I2CM Controller DMA Rx Buffer High part Register */ -+#define AST2600_I2CM_TX_DMA_H 0x60 -+/* I2CM Controller DMA Rx Buffer High part Register */ -+#define AST2600_I2CM_RX_DMA_H 0x64 -+/* I2CS Target DMA Tx Buffer High part Register */ -+#define AST2600_I2CS_TX_DMA_H 0x68 -+/* I2CS Target DMA Rx Buffer High part Register */ -+#define AST2600_I2CS_RX_DMA_H 0x6C ++ /* Pause the coprocessor */ ++ copro_ops->request_access(copro_data); + -+#define AST2600_I2CS_ADDR_CTRL 0x40 ++ /* Change command source back to ARM */ ++ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_ARM); + -+#define AST2600_I2CS_ADDR3_MASK GENMASK(22, 16) -+#define AST2600_I2CS_ADDR2_MASK GENMASK(14, 8) -+#define AST2600_I2CS_ADDR1_MASK GENMASK(6, 0) ++ /* Update cache */ ++ gpio->dcache[GPIO_BANK(offset)] = aspeed_g4_reg_bank_get(gpio, offset, reg_rdata); + -+#define AST2600_I2CM_DMA_LEN_STS 0x48 -+#define AST2600_I2CS_DMA_LEN_STS 0x4C ++ return true; ++} + -+#define AST2600_I2C_GET_TX_DMA_LEN(x) ((x) & GENMASK(12, 0)) -+#define AST2600_I2C_GET_RX_DMA_LEN(x) (((x) & GENMASK(28, 16)) >> 16) ++static void aspeed_g4_copro_release(struct aspeed_gpio *gpio, unsigned int offset) ++{ ++ if (!copro_ops || !gpio->cf_copro_bankmap) ++ return; ++ if (!gpio->cf_copro_bankmap[offset >> 3]) ++ return; ++ if (!copro_ops->release_access) ++ return; + -+/* 0x40 : Target Device Address Register */ -+#define AST2600_I2CS_ADDR3_ENABLE BIT(23) -+#define AST2600_I2CS_ADDR3(x) ((x) << 16) -+#define AST2600_I2CS_ADDR2_ENABLE BIT(15) -+#define AST2600_I2CS_ADDR2(x) ((x) << 8) -+#define AST2600_I2CS_ADDR1_ENABLE BIT(7) -+#define AST2600_I2CS_ADDR1(x) (x) ++ /* Change command source back to ColdFire */ ++ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_COLDFIRE); + -+/* 0x74 : Target Device Address Register */ -+#define MSIC_CONFIG_ACTIMING1 0x74 -+#define MSIC_I2C_SET_TIMEOUT(s, m) (((s) << 16) | (m)) ++ /* Restart the coprocessor */ ++ copro_ops->release_access(copro_data); ++} + -+/* 0x78 : Misc status */ -+#define MSIC_STATUS 0x78 ++static const struct aspeed_gpio_llops aspeed_g4_llops = { ++ .reg_bit_set = aspeed_g4_reg_bit_set, ++ .reg_bit_get = aspeed_g4_reg_bit_get, ++ .reg_bank_get = aspeed_g4_reg_bank_get, ++ .privilege_ctrl = aspeed_g4_privilege_ctrl, ++ .privilege_init = aspeed_g4_privilege_init, ++ .copro_request = aspeed_g4_copro_request, ++ .copro_release = aspeed_g4_copro_release, ++}; + -+/* 0x84 : Byte data log */ -+#define BYTE_DATA_LOG 0x84 ++static void aspeed_g7_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg, bool val) ++{ ++ u32 mask = aspeed_gpio_g7_reg_mask(reg); ++ void __iomem *addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); ++ u32 write_val; + -+#define AST2700_I2CC_GET_BUFF(x) ((x) & GENMASK(7, 0)) ++ if (mask) { ++ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); ++ iowrite32(write_val, addr); ++ } ++} + -+/* 0x8c : Target sirq log */ -+#define AST2700_I2CC_SIRQ_LOG 0x8c -+#define SLAVE_ADDR_SHIFT 8 -+#define SLAVE_ADDR_MASK GENMASK(15, 8) -+#define SADDR_NACK BIT(5) -+#define SLAVE_PKT_DONE BIT(4) -+#define SADDR_HIT BIT(3) -+#define SRX_DONE BIT(2) -+#define STX_DONE BIT(1) -+#define SLAVE_STOP BIT(0) ++static bool aspeed_g7_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) ++{ ++ u32 mask = aspeed_gpio_g7_reg_mask(reg); ++ void __iomem *addr; + -+/* 0x9c : Misc_2 Debounce Setting */ -+#define MSIC2_CONFIG 0x9C -+#define AST2700_DEBOUNCE_MASK GENMASK(7, 0) -+#define AST2700_DEBOUNCE_LEVEL_MAX 0x20 -+#define AST2700_DEBOUNCE_LEVEL_MIN 0x2 ++ addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); ++ if (reg == reg_val) ++ mask = GPIO_G7_CTRL_IN_DATA; + -+#define I2C_TARGET_MSG_BUF_SIZE 4096 ++ if (mask) ++ return field_get(mask, ioread32(addr)); ++ else ++ return 0; ++} + -+#define AST2600_I2C_DMA_SIZE 4096 ++static int aspeed_g7_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) ++{ ++ void __iomem *addr; + -+#define CONTROLLER_TRIGGER_LAST_STOP (AST2600_I2CM_RX_CMD_LAST | AST2600_I2CM_STOP_CMD) -+#define TARGET_TRIGGER_CMD (AST2600_I2CS_ACTIVE_ALL | AST2600_I2CS_PKT_MODE_EN) ++ if (reg == reg_irq_status) { ++ addr = gpio->base + GPIO_G7_IRQ_STS_OFFSET(offset >> 5); ++ return ioread32(addr); ++ } else { ++ return -EOPNOTSUPP; ++ } ++} + -+#define AST2600_I2C_TIMEOUT_CLK 0x1 -+#define AST2700_I2C_TIMEOUT_CLK 0x3 ++static const struct aspeed_gpio_llops aspeed_g7_llops = { ++ .reg_bit_set = aspeed_g7_reg_bit_set, ++ .reg_bit_get = aspeed_g7_reg_bit_get, ++ .reg_bank_get = aspeed_g7_reg_bank_get, ++ .privilege_ctrl = NULL, ++ .privilege_init = NULL, ++ .copro_request = NULL, ++ .copro_release = NULL, ++}; + -+#define AST2600_I2C_TARGET_COUNT 0x3 + /* + * Any banks not specified in a struct aspeed_bank_props array are assumed to + * have the properties: +@@ -1131,7 +1245,14 @@ + + static const struct aspeed_gpio_config ast2400_config = + /* 220 for simplicity, really 216 with two 4-GPIO holes, four at end */ +- { .nr_gpios = 220, .props = ast2400_bank_props, }; ++ { ++ .nr_gpios = 220, ++ .props = ast2400_bank_props, ++ .llops = &aspeed_g4_llops, ++ .debounce_timers_array = debounce_timers, ++ .debounce_timers_num = ARRAY_SIZE(debounce_timers), ++ .require_dcache = true, ++ }; + + static const struct aspeed_bank_props ast2500_bank_props[] = { + /* input output */ +@@ -1143,7 +1264,14 @@ + + static const struct aspeed_gpio_config ast2500_config = + /* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */ +- { .nr_gpios = 232, .props = ast2500_bank_props, }; ++ { ++ .nr_gpios = 232, ++ .props = ast2500_bank_props, ++ .llops = &aspeed_g4_llops, ++ .debounce_timers_array = debounce_timers, ++ .debounce_timers_num = ARRAY_SIZE(debounce_timers), ++ .require_dcache = true, ++ }; + + static const struct aspeed_bank_props ast2600_bank_props[] = { + /* input output */ +@@ -1159,17 +1287,48 @@ + * We expect ngpio being set in the device tree and this is a fallback + * option. + */ +- { .nr_gpios = 208, .props = ast2600_bank_props, }; ++ { ++ .nr_gpios = 208, ++ .props = ast2600_bank_props, ++ .llops = &aspeed_g4_llops, ++ .debounce_timers_array = debounce_timers, ++ .debounce_timers_num = ARRAY_SIZE(debounce_timers), ++ .require_dcache = true, ++ }; + -+enum xfer_mode { -+ BYTE_MODE, -+ BUFF_MODE, -+ DMA_MODE, ++static const struct aspeed_bank_props ast2700_bank_props[] = { ++ /* input output */ ++ { 1, 0x0fffffff, 0x0fffffff }, /* E/F/G/H, 4-GPIO hole */ ++ { 6, 0x00ffffff, 0x00ff0000 }, /* Y/Z/AA */ ++ {}, +}; + -+enum i2c_version { -+ AST2600, -+ AST2700, -+}; ++static const struct aspeed_gpio_config ast2700_config = ++ /* ++ * ast2700 has two controllers one with 212 GPIOs and one with 16 GPIOs. ++ * 216 for simplicity, actual number is 212 (4-GPIO hole in GPIOH) ++ * We expect ngpio being set in the device tree and this is a fallback ++ * option. ++ */ ++ { ++ .nr_gpios = 216, ++ .props = ast2700_bank_props, ++ .llops = &aspeed_g7_llops, ++ .debounce_timers_array = g7_debounce_timers, ++ .debounce_timers_num = ARRAY_SIZE(g7_debounce_timers), ++ .require_dcache = false, ++ }; + + static const struct of_device_id aspeed_gpio_of_table[] = { + { .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, }, + { .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, }, + { .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, }, ++ { .compatible = "aspeed,ast2700-gpio", .data = &ast2700_config, }, + {} + }; + MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table); + +-static int __init aspeed_gpio_probe(struct platform_device *pdev) ++static int aspeed_gpio_probe(struct platform_device *pdev) + { + const struct of_device_id *gpio_id; + struct gpio_irq_chip *girq; +@@ -1202,6 +1361,10 @@ + + gpio->config = gpio_id->data; + ++ if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get || ++ !gpio->config->llops->reg_bank_get) ++ return -EINVAL; + -+struct i2c_divisor { -+ u32 baseclk_idx; -+ u32 divisor; -+ u8 baseclk_limit; -+}; + gpio->chip.parent = &pdev->dev; + err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio); + gpio->chip.ngpio = (u16) ngpio; +@@ -1218,27 +1381,23 @@ + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + +- /* Allocate a cache of the output registers */ +- banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); +- gpio->dcache = devm_kcalloc(&pdev->dev, +- banks, sizeof(u32), GFP_KERNEL); +- if (!gpio->dcache) +- return -ENOMEM; +- +- /* +- * Populate it with initial values read from the HW and switch +- * all command sources to the ARM by default +- */ +- for (i = 0; i < banks; i++) { +- const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; +- void __iomem *addr = bank_reg(gpio, bank, reg_rdata); +- gpio->dcache[i] = ioread32(addr); +- aspeed_gpio_change_cmd_source(gpio, bank, 0, GPIO_CMDSRC_ARM); +- aspeed_gpio_change_cmd_source(gpio, bank, 1, GPIO_CMDSRC_ARM); +- aspeed_gpio_change_cmd_source(gpio, bank, 2, GPIO_CMDSRC_ARM); +- aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM); ++ if (gpio->config->require_dcache) { ++ /* Allocate a cache of the output registers */ ++ banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); ++ gpio->dcache = devm_kcalloc(&pdev->dev, banks, sizeof(u32), GFP_KERNEL); ++ if (!gpio->dcache) ++ return -ENOMEM; ++ /* ++ * Populate it with initial values read from the HW ++ */ ++ for (i = 0; i < banks; i++) ++ gpio->dcache[i] = ++ gpio->config->llops->reg_bank_get(gpio, (i << 5), reg_rdata); + } + ++ if (gpio->config->llops->privilege_init) ++ gpio->config->llops->privilege_init(gpio); + -+struct ast2600_i2c_bus { -+ struct i2c_adapter adap; -+ struct device *dev; -+ void __iomem *reg_base; -+ struct regmap *global_regs; -+ struct reset_control *rst; -+ struct clk *clk; -+ struct i2c_timings timing_info; -+ struct completion cmd_complete; -+ struct i2c_msg *msgs; -+ u8 *controller_safe_buf; -+ dma_addr_t controller_dma_addr; -+ u32 apb_clk; -+ struct i2c_divisor clk_divisor; -+ u32 timeout; -+ int irq; -+ int cmd_err; -+ int msgs_index; -+ int msgs_count; -+ int controller_xfer_cnt; -+ size_t buf_index; -+ size_t buf_size; -+ enum xfer_mode mode; -+ enum i2c_version version; -+ bool multi_master; -+ u32 debounce_level; -+ /* Buffer mode */ -+ void __iomem *buf_base; -+ /* smbus alert */ -+ bool alert_enable; -+ struct i2c_smbus_alert_setup alert_data; -+ struct i2c_client *ara; -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ int target_operate; -+ int previous_idx; -+ unsigned char *target_dma_buf; -+ dma_addr_t target_dma_addr; -+ u8 target_attached; -+ struct i2c_client *multi_target[AST2600_I2C_TARGET_COUNT]; -+ struct i2c_client *target; -+#endif -+}; + /* Set up an irqchip */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) +@@ -1270,13 +1429,14 @@ + } + + static struct platform_driver aspeed_gpio_driver = { ++ .probe = aspeed_gpio_probe, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = aspeed_gpio_of_table, + }, + }; + +-module_platform_driver_probe(aspeed_gpio_driver, aspeed_gpio_probe); ++module_platform_driver(aspeed_gpio_driver); + + MODULE_DESCRIPTION("Aspeed GPIO Driver"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/aspeed/Kconfig b/drivers/gpu/drm/aspeed/Kconfig +--- a/drivers/gpu/drm/aspeed/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpu/drm/aspeed/Kconfig 2026-09-09 15:51:29.983460728 +0000 +@@ -4,6 +4,7 @@ + depends on DRM && OF + depends on (COMPILE_TEST || ARCH_ASPEED) + depends on MMU ++ select FB + select DRM_KMS_HELPER + select DRM_GEM_DMA_HELPER + select DMA_CMA if HAVE_DMA_CONTIGUOUS +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h +--- a/drivers/gpu/drm/aspeed/aspeed_gfx.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h 2026-09-09 15:51:44.558240489 +0000 +@@ -8,14 +8,32 @@ + struct drm_device drm; + void __iomem *base; + struct clk *clk; +- struct reset_control *rst; ++ struct reset_control *rst_crt; ++ struct reset_control *rst_engine; + struct regmap *scu; ++ struct regmap *scu1; ++ struct regmap *dp; ++ struct regmap *dpmcu; ++ struct regmap *pcie_ep; ++ ++ u8 dp_support; ++ u8 pcie_advance; ++ u8 pcie_active; + + u32 dac_reg; + u32 int_clr_reg; + u32 vga_scratch_reg; + u32 throd_val; + u32 scan_line_max; ++ u32 flags; ++ u32 pcie_int_reg; ++ u32 pcie_int_mask; ++ u32 pcie_int_l_to_h; ++ u32 pcie_int_h_to_l; ++ u32 pcie_link_reg; ++ u32 pcie_link_bit; ++ u32 soc_crt_bit; ++ u32 soc_dp_bit; + + struct drm_simple_display_pipe pipe; + struct drm_connector connector; +@@ -83,6 +101,10 @@ + #define CRT_CTRL_VBLANK_LINE(x) (((x) << 20) & CRT_CTRL_VBLANK_LINE_MASK) + #define CRT_CTRL_VBLANK_LINE_MASK GENMASK(31, 20) + ++/* CURSOR define */ ++#define CRT_CTRL_CURSOR0 0x3f3f ++#define CRT_CTRL_CURSOR1 0xfff1fff ++ + /* CRT_HORIZ0 */ + #define CRT_H_TOTAL(x) (x) + #define CRT_H_DE(x) ((x) << 16) +@@ -106,3 +128,58 @@ + /* CRT_THROD */ + #define CRT_THROD_LOW(x) (x) + #define CRT_THROD_HIGH(x) ((x) << 8) + -+static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) -+{ -+ unsigned long base_clk[16]; -+ int baseclk_idx = 0; -+ int divisor = 0; -+ u32 clk_div_reg; -+ u32 scl_low; -+ u32 scl_high; -+ u32 data; ++/* SCU control */ ++#define G4_DISABLE_D2_PLL BIT(4) ++#define G4_40_CLK 0x46314 ++#define G6_CLK_SOURCE 0x300 ++#define G6_CLK_SOURCE_MASK (BIT(8) | BIT(9) | BIT(10)) ++#define G6_CLK_SOURCE_HPLL (BIT(8) | BIT(9) | BIT(10)) ++#define G6_CLK_SOURCE_USB BIT(9) ++#define G6_CLK_SEL3 0x308 ++#define G6_CLK_DIV_MASK 0x3F000 ++#define G6_CLK_DIV_16 (BIT(16) | BIT(15) | BIT(13) | BIT(12)) ++#define G6_USB_40_CLK BIT(9) + -+ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); ++/* GFX FLAGS */ ++#define RESET_MASK BIT(0) ++#define RESET_G6 BIT(0) ++#define CLK_MASK (BIT(4) | BIT(5) | BIT(6)) ++#define CLK_G4 BIT(4) ++#define CLK_G6 BIT(5) ++#define CLK_G7 BIT(6) ++#define ADDR_64 BIT(12) + -+ for (int i = 0; i < ARRAY_SIZE(base_clk); i++) { -+ if (i == 0) -+ base_clk[i] = i2c_bus->apb_clk; -+ else if (i < 5) -+ base_clk[i] = (i2c_bus->apb_clk * 2) / -+ (((clk_div_reg >> ((i - 1) * 8)) & GENMASK(7, 0)) + 2); -+ else -+ base_clk[i] = base_clk[4] >> (i - 4); -+ if ((base_clk[i] / i2c_bus->timing_info.bus_freq_hz) <= 32) { -+ baseclk_idx = i; -+ divisor = DIV_ROUND_UP(base_clk[i], i2c_bus->timing_info.bus_freq_hz); -+ break; -+ } -+ } ++/* PCIE interrupt */ ++#define PCIE_PERST_L_T_H_G5 BIT(18) ++#define PCIE_PERST_H_T_L_G5 BIT(19) ++#define PCIE_PERST_L_T_H_G7 BIT(3) ++#define PCIE_PERST_H_T_L_G7 BIT(2) + -+ baseclk_idx = min(baseclk_idx, 15); -+ divisor = min(divisor, 32); -+ scl_low = min(divisor * 9 / 16 - 1, 15); -+ scl_high = (divisor - scl_low - 2) & GENMASK(3, 0); -+ data = (scl_high - 1) << 20 | scl_high << 16 | scl_low << 12 | baseclk_idx; ++/* PCIE end pointer define */ ++#define PCIE_LINK_REG_G5 0xC0 ++#define PCIE_LINK_STATUS_G5 BIT(5) ++#define PCIE_LINK_REG_G7 0x358 ++#define PCIE_LINK_STATUS_G7 BIT(8) + -+ if (i2c_bus->timeout) { -+ i2c_bus->timeout = min(i2c_bus->timeout, 31); -+ data |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); -+ data |= AST2600_I2CC_TOUTBASECLK(AST2600_I2C_TIMEOUT_CLK); -+ } ++/* Adaptor function define */ ++/* AST2600: DP adaptor define */ ++#define DP_26_CP_NAME "aspeed,ast2600-displayport" ++#define DP_26_MCU_CP_NAME "aspeed,ast2600-displayport-mcu" ++/* AST2600 */ ++#define SCU_DP_STATUS 0x100 /* SCU100 VGA function handshake */ ++/* AST2700: DP adaptor define */ ++#define DP_27_CP_NAME "aspeed,ast2700-displayport" ++#define DP_27_MCU_CP_NAME "aspeed,ast2700-displayport-mcu" ++#define SCU_PCIE0_DP_STATUS 0x900 /* SCU900 PCIE0 handshake */ ++#define SCU_PCIE1_DP_STATUS 0x910 /* SCU910 PCIE1 handshake */ ++#define DP_LOCATE_PCIE1 BIT(8) /* DP located on PCIE1 */ + -+ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++/* AST DP */ ++#define DP_EXECUTE 0x2E /* DP Status */ ++#define DP_SOURCE 0xb8 /* DPB8 dp source */ ++#define DP_CONTROL_FROM_SOC (BIT(24) | BIT(28)) ++/* AST DP MCU */ ++#define DP_RESOLUTION 0xde0 /* DPMCUDE0 dp resolution */ ++#define DP_800 0x01050020 /* 800 x 600 60Hz */ ++#define DP_1024 0x010a0020 /* 1024 x 768 70Hz */ +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +--- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c 2026-09-09 15:51:44.552240580 +0000 +@@ -23,6 +23,45 @@ + return container_of(pipe, struct aspeed_gfx, pipe); + } + ++static void aspeed_gfx_set_g4_clock(struct aspeed_gfx *priv) ++{ ++ /* turn on d2 pll for soc disply at ast2400 */ ++ regmap_update_bits(priv->scu, priv->dac_reg, G4_DISABLE_D2_PLL, 0); ++ /* apply 800 x 600 @ 60 for soc disply at ast2400 */ ++ writel(G4_40_CLK, priv->base + CRT_MISC); +} + -+static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) ++static void aspeed_gfx_set_g6_clock_source(struct aspeed_gfx *priv, int mode_width) +{ -+ unsigned long base_clk; -+ int baseclk_idx = 0; -+ int divisor = 0; -+ u32 clk_div_reg; -+ u32 scl_low; -+ u32 scl_high; -+ u32 data; -+ u8 divid_term = 0; -+ -+ /* The i2c minmum ac-timing is 12KHz */ -+ if (i2c_bus->timing_info.bus_freq_hz < AST2700_MIN_AC_TIMING) { -+ dev_err(i2c_bus->dev, "The frequency could not be lower than 12KHz.\n"); -+ i2c_bus->timing_info.bus_freq_hz = AST2700_MIN_AC_TIMING; -+ } -+ -+ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); -+ -+ /* Find the most used ac-timing */ -+ for (int i = 0; i < 3; i++) { -+ divid_term = ((clk_div_reg >> (i << 3)) & GENMASK(7, 0)); -+ base_clk = (i2c_bus->apb_clk) / (divid_term + 1); -+ if ((base_clk / i2c_bus->timing_info.bus_freq_hz) <= 32) { -+ baseclk_idx = divid_term; -+ divisor = DIV_ROUND_UP(base_clk, i2c_bus->timing_info.bus_freq_hz); -+ break; -+ } -+ } -+ -+ /* Can't find a ac-timing then search a fitting one */ -+ if (baseclk_idx == 0) { -+ for (int i = 0; i < 0x100; i++) { -+ base_clk = (i2c_bus->apb_clk) / (i + 1); -+ if ((base_clk / i2c_bus->timing_info.bus_freq_hz) <= 32) { -+ baseclk_idx = i; -+ divisor = DIV_ROUND_UP(base_clk, i2c_bus->timing_info.bus_freq_hz); -+ break; -+ } -+ } -+ } -+ -+ baseclk_idx = min(baseclk_idx, 0xff); -+ divisor = min(divisor, 32); -+ scl_low = min((DIV_ROUND_UP(divisor * 9, 16)) - 1, 15); -+ scl_high = (divisor - scl_low - 2) & GENMASK(3, 0); -+ data = (scl_high - 1) << 20 | scl_high << 16 | scl_low << 12 | baseclk_idx; ++ regmap_update_bits(priv->scu, G6_CLK_SOURCE, G6_CLK_SOURCE_MASK, 0x0); ++ regmap_update_bits(priv->scu, G6_CLK_SEL3, G6_CLK_DIV_MASK, 0x0); + -+ if (i2c_bus->timeout) { -+ i2c_bus->timeout = min(i2c_bus->timeout, 255); -+ writel(MSIC_I2C_SET_TIMEOUT(i2c_bus->timeout, 0), -+ i2c_bus->reg_base + MSIC_CONFIG_ACTIMING1); -+ /* timeout_base set as 1ms */ -+ data |= AST2600_I2CC_TOUTBASECLK(AST2700_I2C_TIMEOUT_CLK); ++ switch (mode_width) { ++ case 1024: ++ /* hpll div 16 = 75Mhz */ ++ regmap_update_bits(priv->scu, G6_CLK_SOURCE, G6_CLK_SOURCE_MASK, G6_CLK_SOURCE_HPLL); ++ regmap_update_bits(priv->scu, G6_CLK_SEL3, G6_CLK_DIV_MASK, G6_CLK_DIV_16); ++ break; ++ case 800: ++ default: ++ /* usb 40Mhz */ ++ regmap_update_bits(priv->scu, G6_CLK_SOURCE, G6_CLK_SOURCE_MASK, G6_CLK_SOURCE_USB); ++ break; + } -+ -+ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); +} + -+static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus) ++static void aspeed_gfx_set_g7_clock(struct aspeed_gfx *priv) +{ -+ u32 state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ int ret = 0; -+ int r; -+ -+ dev_dbg(i2c_bus->dev, "%d-bus recovery bus [%x]\n", i2c_bus->adap.nr, state); ++ /* apply 800 x 600 @ 60 on ast2700 */ ++ regmap_update_bits(priv->scu, 0x288, BIT(14), BIT(14)); ++ regmap_write(priv->scu, 0x340, 0x00190002); + -+ reinit_completion(&i2c_bus->cmd_complete); -+ i2c_bus->cmd_err = 0; ++ /* apply 800 x 600 @ 60 on ast2700 DAC */ ++ /* Move the scu1.d0 to the aspeed_gfx_enable_controller first check */ ++ regmap_write(priv->scu1, 0x324, 0x00000007); ++ regmap_write(priv->scu1, 0x320, 0x1048000F); ++} + -+ /* Check 0x14's SDA and SCL status */ -+ state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ if (!(state & AST2600_I2CC_SDA_LINE_STS) && (state & AST2600_I2CC_SCL_LINE_STS)) { -+ writel(AST2600_I2CM_RECOVER_CMD_EN, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); -+ r = wait_for_completion_timeout(&i2c_bus->cmd_complete, i2c_bus->adap.timeout); -+ if (r == 0) { -+ dev_dbg(i2c_bus->dev, "recovery timed out\n"); -+ return -ETIMEDOUT; -+ } else if (i2c_bus->cmd_err) { -+ dev_dbg(i2c_bus->dev, "recovery error\n"); -+ ret = -EPROTO; -+ } + static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) + { + struct drm_crtc *crtc = &priv->pipe.crtc; +@@ -59,11 +98,24 @@ + u32 ctrl1 = readl(priv->base + CRT_CTRL1); + u32 ctrl2 = readl(priv->base + CRT_CTRL2); + +- /* Set DAC source for display output to Graphics CRT (GFX) */ +- regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), BIT(16)); ++ /* change the display source is coming from soc display */ ++ if (!priv->pcie_advance || !priv->pcie_active) { ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, priv->soc_crt_bit); ++ if (priv->dp_support) ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, priv->soc_dp_bit); ++ if ((priv->flags & CLK_MASK) == CLK_G7) ++ regmap_update_bits(priv->scu1, 0xd0, BIT(10), BIT(10)); + } + -+ /* Recovery done */ -+ state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ if (state & AST2600_I2CC_BUS_BUSY_STS) { -+ dev_dbg(i2c_bus->dev, "Can't recover bus [%x]\n", state); -+ ret = -EPROTO; -+ } ++ /* remove the cursor and osd usage */ ++ ctrl1 &= ~(CRT_CTRL_HW_CURSOR_EN | CRT_CTRL_OSD_EN); + + writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1); + writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); + -+ return ret; ++ /* trigger cursor position to apply cursor disable */ ++ writel(CRT_CTRL_CURSOR0, priv->base + CRT_CURSOR0); ++ writel(CRT_CTRL_CURSOR1, priv->base + CRT_CURSOR1); + } + + static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv) +@@ -74,7 +126,42 @@ + writel(ctrl1 & ~CRT_CTRL_EN, priv->base + CRT_CTRL1); + writel(ctrl2 & ~CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); + +- regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), 0); ++ /* Set display source for display output to pcie host display */ ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, 0); ++ if (priv->dp_support) ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, 0); +} + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+static void ast2700_i2c_get_target(struct ast2600_i2c_bus *i2c_bus, u8 addr) ++static void aspeed_gfx_set_clk(struct aspeed_gfx *priv, int mode_width) +{ -+ u8 i = 0; -+ bool target_find = false; -+ -+ /* find target by address */ -+ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { -+ if (i2c_bus->multi_target[i]) { -+ if (i2c_bus->multi_target[i]->addr == addr) { -+ dev_dbg(i2c_bus->dev, "address [%x] on %d\n", addr, i); -+ i2c_bus->target = i2c_bus->multi_target[i]; -+ target_find = true; -+ } -+ } ++ switch (priv->flags & CLK_MASK) { ++ case CLK_G4: ++ aspeed_gfx_set_g4_clock(priv); ++ break; ++ case CLK_G6: ++ aspeed_gfx_set_g6_clock_source(priv, mode_width); ++ break; ++ case CLK_G7: ++ aspeed_gfx_set_g7_clock(priv); ++ break; ++ default: ++ break; + } -+ -+ if (!target_find) -+ dev_err(i2c_bus->dev, "address [%x] could not find\n", addr); +} + -+static void ast2700_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 isr) ++static void aspeed_gfx_dp_mode_set(struct aspeed_gfx *priv, int mode_width) +{ -+ int target_rx_len = 0; -+ u32 cmd = 0; -+ u8 value; -+ int i; -+ u32 sirq_log; -+ u32 sts; ++ switch (mode_width) { ++ case 1024: ++ /* hpll div 16 = 75Mhz */ ++ regmap_write(priv->dpmcu, DP_RESOLUTION, DP_1024); ++ break; ++ case 800: ++ default: ++ /* usb 40Mhz */ ++ regmap_write(priv->dpmcu, DP_RESOLUTION, DP_800); ++ break; ++ } + } + + static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) +@@ -87,6 +174,8 @@ + if (err) + return; + ++ aspeed_gfx_set_clk(priv, m->hdisplay); + -+ writel(AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_WAIT_RX_DMA, -+ i2c_bus->reg_base + AST2600_I2CS_ISR); -+ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + #if 0 + /* TODO: we have only been able to test with the 40MHz USB clock. The + * clock is fixed, so we cannot adjust it here. */ +@@ -137,6 +226,10 @@ + * per line, rounded up) + */ + writel(priv->throd_val, priv->base + CRT_THROD); + -+ sts = isr & ~(AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_ADDR_NAK_MASK); -+ /* Handle i2c target timeout condition */ -+ if (AST2600_I2CS_INACTIVE_TO & sts) { -+ dev_dbg(i2c_bus->dev, "The target timeout occurs isr: 0x%08x.\n", isr); -+ /* Reset timeout counter */ -+ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & -+ AST2600_I2CC_AC_TIMING_MASK; ++ /* set the dp mode index */ ++ if (priv->dp_support) ++ aspeed_gfx_dp_mode_set(priv, m->hdisplay); + } + + static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe *pipe, +@@ -187,12 +280,17 @@ + gem = drm_fb_dma_get_gem_obj(fb, 0); + if (!gem) + return; +- writel(gem->dma_addr, priv->base + CRT_ADDR); + -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ ac_timing |= AST2700_I2CC_TTIMEOUT(i2c_bus->timeout); -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ /* clear sirq log */ -+ while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) { -+ /* assign the target client*/ -+ if (sirq_log & SADDR_HIT) { -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ } -+ }; -+ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ } -+ return; -+ } ++ if (priv->flags & ADDR_64) ++ writel((gem->dma_addr >> 2), priv->base + CRT_ADDR); ++ else ++ writel(gem->dma_addr, priv->base + CRT_ADDR); + } + + static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) + { + struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + -+ if (AST2600_I2CS_ABNOR_STOP & sts) { -+ dev_err(i2c_bus->dev, "The target abnomal protocol occurs isr: 0x%08x.\n", isr); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ /* clear sirq log */ -+ while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) { -+ /* assign the target client*/ -+ if (sirq_log & SADDR_HIT) { -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ } -+ }; -+ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ } -+ return; -+ } + u32 reg = readl(priv->base + CRT_CTRL1); + + /* Clear pending VBLANK IRQ */ +@@ -207,6 +305,7 @@ + static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) + { + struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + -+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR); + u32 reg = readl(priv->base + CRT_CTRL1); + + reg &= ~CRT_CTRL_VERTICAL_INTR_EN; +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c 2026-09-09 15:51:44.565240383 +0000 +@@ -63,6 +63,15 @@ + u32 vga_scratch_reg; /* VGA scratch register in SCU */ + u32 throd_val; /* Default Threshold Seting */ + u32 scan_line_max; /* Max memory size of one scan line */ ++ u32 gfx_flags; /* Flags for gfx chip caps */ ++ u32 pcie_int_reg; /* pcie interrupt */ ++ u32 pcie_int_mask; /* pcie PERST# mask */ ++ u32 pcie_int_l_to_h; /* pcie PERST# low to high */ ++ u32 pcie_int_h_to_l; /* pcie PERST# high to low */ ++ u32 pcie_link_reg; /* pcie link status offset */ ++ u32 pcie_link_bit; /* pcie link status bit */ ++ u32 soc_crt_bit; /* soc display crt switch flag*/ ++ u32 soc_dp_bit; /* soc display dp switch flag*/ + }; + + static const struct aspeed_gfx_config ast2400_config = { +@@ -71,6 +80,15 @@ + .vga_scratch_reg = 0x50, + .throd_val = CRT_THROD_LOW(0x1e) | CRT_THROD_HIGH(0x12), + .scan_line_max = 64, ++ .gfx_flags = CLK_G4, ++ .pcie_int_reg = 0x0, ++ .pcie_int_mask = 0x0, ++ .pcie_int_l_to_h = 0x0, ++ .pcie_int_h_to_l = 0x0, ++ .pcie_link_reg = 0x0, ++ .pcie_link_bit = 0x0, ++ .soc_crt_bit = BIT(16), ++ .soc_dp_bit = 0x0, + }; + + static const struct aspeed_gfx_config ast2500_config = { +@@ -79,6 +97,15 @@ + .vga_scratch_reg = 0x50, + .throd_val = CRT_THROD_LOW(0x24) | CRT_THROD_HIGH(0x3c), + .scan_line_max = 128, ++ .gfx_flags = 0, ++ .pcie_int_reg = 0x18, ++ .pcie_int_mask = (PCIE_PERST_L_T_H_G5 | PCIE_PERST_H_T_L_G5), ++ .pcie_int_l_to_h = PCIE_PERST_L_T_H_G5, ++ .pcie_int_h_to_l = PCIE_PERST_H_T_L_G5, ++ .pcie_link_reg = PCIE_LINK_REG_G5, ++ .pcie_link_bit = PCIE_LINK_STATUS_G5, ++ .soc_crt_bit = BIT(16), ++ .soc_dp_bit = 0x0, + }; + + static const struct aspeed_gfx_config ast2600_config = { +@@ -87,12 +114,39 @@ + .vga_scratch_reg = 0x50, + .throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70), + .scan_line_max = 128, ++ .gfx_flags = RESET_G6 | CLK_G6, ++ .pcie_int_reg = 0x560, ++ .pcie_int_mask = (PCIE_PERST_L_T_H_G5 | PCIE_PERST_H_T_L_G5), ++ .pcie_int_l_to_h = PCIE_PERST_L_T_H_G5, ++ .pcie_int_h_to_l = PCIE_PERST_H_T_L_G5, ++ .pcie_link_reg = PCIE_LINK_REG_G5, ++ .pcie_link_bit = PCIE_LINK_STATUS_G5, ++ .soc_crt_bit = BIT(16), ++ .soc_dp_bit = BIT(18), ++}; + -+ switch (sts) { -+ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_RX_DMA | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); -+ } -+ } -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++static const struct aspeed_gfx_config ast2700_config = { ++ .dac_reg = 0x414, ++ .int_clear_reg = 0x68, ++ .vga_scratch_reg = 0x50, ++ .throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70), ++ .scan_line_max = 128, ++ .gfx_flags = CLK_G7 | ADDR_64, ++ .pcie_int_reg = 0x1D4, ++ .pcie_int_mask = (PCIE_PERST_L_T_H_G7 | PCIE_PERST_H_T_L_G7), ++ .pcie_int_l_to_h = PCIE_PERST_L_T_H_G7, ++ .pcie_int_h_to_l = PCIE_PERST_H_T_L_G7, ++ .pcie_link_reg = PCIE_LINK_REG_G7, ++ .pcie_link_bit = PCIE_LINK_STATUS_G7, ++ .soc_crt_bit = BIT(11), ++ .soc_dp_bit = BIT(9), + }; + + static const struct of_device_id aspeed_gfx_match[] = { + { .compatible = "aspeed,ast2400-gfx", .data = &ast2400_config }, + { .compatible = "aspeed,ast2500-gfx", .data = &ast2500_config }, + { .compatible = "aspeed,ast2600-gfx", .data = &ast2600_config }, ++ { .compatible = "aspeed,ast2700-gfx", .data = &ast2700_config }, + { }, + }; + MODULE_DEVICE_TABLE(of, aspeed_gfx_match); +@@ -105,6 +159,7 @@ + + static int aspeed_gfx_setup_mode_config(struct drm_device *drm) + { ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); + int ret; + + ret = drmm_mode_config_init(drm); +@@ -113,13 +168,67 @@ + + drm->mode_config.min_width = 0; + drm->mode_config.min_height = 0; +- drm->mode_config.max_width = 800; +- drm->mode_config.max_height = 600; ++ ++ switch (priv->flags & CLK_MASK) { ++ case CLK_G6: ++ drm->mode_config.max_width = 1024; ++ drm->mode_config.max_height = 768; + break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ /* bug workaround */ -+ if (sirq_log & SADDR_HIT) { -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); ++ default: ++ drm->mode_config.max_width = 800; ++ drm->mode_config.max_height = 600; ++ break; ++ } ++ + drm->mode_config.funcs = &aspeed_gfx_mode_config_funcs; + + return ret; + } + ++static irqreturn_t aspeed_host_irq_handler(int irq, void *data) ++{ ++ struct drm_device *drm = data; ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ u32 reg; ++ ++ regmap_read(priv->scu, priv->pcie_int_reg, ®); ++ ++ if (reg & priv->pcie_int_mask) { ++ if (reg & priv->pcie_int_l_to_h) { ++ dev_dbg(drm->dev, "pcie active.\n"); ++ /*Change the DP back to host*/ ++ if (priv->dp_support) { ++ /*Change the DP back to host*/ ++ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, 0); ++ dev_dbg(drm->dev, "dp set at 0 int L_T_H.\n"); ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, 0); + } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ } -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ ++ /*Change the CRT back to host*/ ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, 0); ++ if ((priv->flags & CLK_MASK) == CLK_G7) ++ regmap_update_bits(priv->scu1, 0xD0, BIT(10), 0); ++ } else if (reg & priv->pcie_int_h_to_l) { ++ dev_dbg(drm->dev, "pcie de-active.\n"); ++ /*Change the DP into host*/ ++ if (priv->dp_support) { ++ /*Change the DP back to soc*/ ++ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); ++ dev_dbg(drm->dev, "dp set at 11 int H_T_L.\n"); ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, priv->soc_dp_bit); + } ++ ++ /*Change the CRT into soc*/ ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, priv->soc_crt_bit); ++ if ((priv->flags & CLK_MASK) == CLK_G7) ++ regmap_update_bits(priv->scu1, 0xD0, BIT(10), BIT(10)); + } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ + static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) + { + struct drm_device *drm = data; +@@ -137,6 +246,158 @@ + return IRQ_NONE; + } + ++static int aspeed_pcie_active_detect(struct drm_device *drm) ++{ ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ u32 reg = 0; ++ ++ /* map pcie ep resource */ ++ priv->pcie_ep = syscon_regmap_lookup_by_compatible("aspeed,ast2500-pcie-ep"); ++ if (IS_ERR(priv->pcie_ep)) { ++ priv->pcie_ep = syscon_regmap_lookup_by_compatible("aspeed,ast2600-pcie-phy"); ++ if (IS_ERR(priv->pcie_ep)) { ++ priv->pcie_ep = syscon_regmap_lookup_by_compatible("aspeed,ast2700-pcie-phy"); ++ if (IS_ERR(priv->pcie_ep)) { ++ dev_err(drm->dev, "failed to find pcie_ep regmap\n"); ++ return PTR_ERR(priv->pcie_ep); ++ } + } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ } ++ ++ /* check pcie rst status */ ++ regmap_read(priv->pcie_ep, priv->pcie_link_reg, ®); ++ ++ /* host vga is on or not */ ++ if (reg & priv->pcie_link_bit) ++ priv->pcie_active = 0x1; ++ else ++ priv->pcie_active = 0x0; ++ ++ dev_dbg(drm->dev, "pcie_active %x\n", priv->pcie_active); ++ ++ return 0; ++} ++ ++static int aspeed_adaptor_detect(struct drm_device *drm) ++{ ++ struct platform_device *pdev = to_platform_device(drm->dev); ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ struct device_node *np = pdev->dev.of_node; ++ ++ u32 dp_status_offset = 0, reg = 0; ++ ++ switch (priv->flags & CLK_MASK) { ++ case CLK_G6: ++ /* check AST DP is executed or not*/ ++ regmap_read(priv->scu, SCU_DP_STATUS, ®); ++ if (((reg >> 8) & DP_EXECUTE) == DP_EXECUTE) { ++ priv->dp_support = 0x1; ++ ++ priv->dp = syscon_regmap_lookup_by_compatible(DP_26_CP_NAME); ++ if (IS_ERR(priv->dp)) { ++ dev_err(drm->dev, "failed to find DP regmap\n"); ++ return PTR_ERR(priv->dp); + } -+ } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_SLAVE_MATCH | -+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ ++ priv->dpmcu = syscon_regmap_lookup_by_compatible(DP_26_MCU_CP_NAME); ++ if (IS_ERR(priv->dpmcu)) { ++ dev_err(drm->dev, "failed to find DP MCU regmap\n"); ++ return PTR_ERR(priv->dpmcu); + } ++ ++ /* change the dp setting is coming from soc display */ ++ if (!priv->pcie_active) ++ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); + } -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; + break; -+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | -+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ /* workaround: false alarm target match check */ -+ if (sirq_log & SADDR_HIT) { -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ } -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ case CLK_G7: ++ /* check AST DP is located on PCIE0 or PCIE1 */ ++ regmap_read(priv->scu, priv->dac_reg, ®); ++ ++ if (reg & DP_LOCATE_PCIE1) ++ dp_status_offset = SCU_PCIE1_DP_STATUS; ++ else ++ dp_status_offset = SCU_PCIE0_DP_STATUS; ++ ++ /* check AST DP is executed or not*/ ++ regmap_read(priv->scu, dp_status_offset, ®); ++ if (((reg >> 8) & DP_EXECUTE) == DP_EXECUTE) { ++ priv->dp_support = 0x1; ++ ++ priv->dp = syscon_regmap_lookup_by_compatible(DP_27_CP_NAME); ++ if (IS_ERR(priv->dp)) { ++ dev_err(drm->dev, "failed to find DP regmap\n"); ++ return PTR_ERR(priv->dp); + } -+ } -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ /* workaround new target match */ -+ if (sirq_log & SADDR_HIT) { -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); ++ ++ priv->dpmcu = syscon_regmap_lookup_by_compatible(DP_27_MCU_CP_NAME); ++ if (IS_ERR(priv->dpmcu)) { ++ dev_err(drm->dev, "failed to find DP MCU regmap\n"); ++ return PTR_ERR(priv->dpmcu); + } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ ++ /* change the dp setting is coming from soc display */ ++ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); + } -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ ++ /* get the scu1 for DAC setting */ ++ priv->scu1 = syscon_regmap_lookup_by_phandle(np, "syscon_io"); ++ if (IS_ERR(priv->scu1)) { ++ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2700-scu1"); ++ if (IS_ERR(priv->scu1)) { ++ dev_err(drm->dev, "failed to find SCU1 regmap\n"); ++ return PTR_ERR(priv->scu1); + } + } -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (sirq_log & SADDR_HIT) { -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ /* workaround: not clear target match due to wait next isr check tx or rx */ -+ isr &= ~AST2600_I2CS_SLAVE_MATCH; -+ break; -+ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_TX_NAK | -+ AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; -+ break; -+ case AST2600_I2CS_TX_ACK | AST2600_I2CS_WAIT_TX_DMA: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ + break; -+ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH | -+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); -+ } -+ } -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target = NULL; -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ default: ++ priv->dp_support = 0x0; ++ priv->dp = NULL; ++ priv->dpmcu = NULL; + break; -+ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); -+ } ++ } ++ return 0; ++} ++ ++static int aspeed_gfx_reset(struct drm_device *drm) ++{ ++ struct platform_device *pdev = to_platform_device(drm->dev); ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ ++ switch (priv->flags & RESET_MASK) { ++ case RESET_G6: ++ priv->rst_crt = devm_reset_control_get(&pdev->dev, "crt"); ++ if (IS_ERR(priv->rst_crt)) { ++ dev_err(&pdev->dev, ++ "missing or invalid crt reset controller device tree entry"); ++ return PTR_ERR(priv->rst_crt); + } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); ++ reset_control_deassert(priv->rst_crt); ++ ++ priv->rst_engine = devm_reset_control_get(&pdev->dev, "engine"); ++ if (IS_ERR(priv->rst_engine)) { ++ dev_err(&pdev->dev, ++ "missing or invalid engine reset controller device tree entry"); ++ return PTR_ERR(priv->rst_engine); + } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ reset_control_deassert(priv->rst_engine); + break; -+ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); -+ } -+ } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); ++ ++ default: ++ priv->rst_crt = devm_reset_control_get_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(priv->rst_crt)) { ++ dev_err(&pdev->dev, ++ "missing or invalid reset controller device tree entry"); ++ return PTR_ERR(priv->rst_crt); + } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ reset_control_deassert(priv->rst_crt); + break; -+ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ } ++ ++ return 0; ++} ++ + static int aspeed_gfx_load(struct drm_device *drm) + { + struct platform_device *pdev = to_platform_device(drm->dev); +@@ -144,6 +405,7 @@ + struct device_node *np = pdev->dev.of_node; + const struct aspeed_gfx_config *config; + struct resource *res; ++ u64 dma_mask = 0; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -160,13 +422,40 @@ + priv->vga_scratch_reg = config->vga_scratch_reg; + priv->throd_val = config->throd_val; + priv->scan_line_max = config->scan_line_max; ++ priv->flags = config->gfx_flags; ++ priv->pcie_int_reg = config->pcie_int_reg; ++ priv->pcie_int_mask = config->pcie_int_mask; ++ priv->pcie_int_l_to_h = config->pcie_int_l_to_h; ++ priv->pcie_int_h_to_l = config->pcie_int_h_to_l; ++ priv->pcie_link_reg = config->pcie_link_reg; ++ priv->pcie_link_bit = config->pcie_link_bit; ++ priv->soc_crt_bit = config->soc_crt_bit; ++ priv->soc_dp_bit = config->soc_dp_bit; ++ ++ /* Add pcie auto detect if the register has been assigned */ ++ if (priv->pcie_int_reg != 0x0) ++ priv->pcie_advance = 1; ++ else ++ priv->pcie_advance = 0; ++ ++ /* Set the DMA mask by addr */ ++ if (priv->flags & ADDR_64) ++ dma_mask = DMA_BIT_MASK(64); ++ else ++ dma_mask = DMA_BIT_MASK(32); + + priv->scu = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(priv->scu)) { +- priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu"); ++ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2400-scu"); + if (IS_ERR(priv->scu)) { +- dev_err(&pdev->dev, "failed to find SCU regmap\n"); +- return PTR_ERR(priv->scu); ++ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu"); ++ if (IS_ERR(priv->scu)) { ++ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2600-scu"); ++ if (IS_ERR(priv->scu)) { ++ dev_err(&pdev->dev, "failed to find SCU regmap\n"); ++ return PTR_ERR(priv->scu); ++ } + } + } + } + +@@ -177,19 +466,18 @@ + return ret; + } + +- ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32)); ++ ret = dma_set_mask_and_coherent(drm->dev, dma_mask); + if (ret) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", ret); + return ret; + } + +- priv->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (IS_ERR(priv->rst)) { ++ ret = aspeed_gfx_reset(drm); ++ if (ret) { + dev_err(&pdev->dev, + "missing or invalid reset controller device tree entry"); +- return PTR_ERR(priv->rst); ++ return ret; + } +- reset_control_deassert(priv->rst); + + priv->clk = devm_clk_get(drm->dev, NULL); + if (IS_ERR(priv->clk)) { +@@ -199,6 +487,22 @@ + } + clk_prepare_enable(priv->clk); + ++ if (priv->pcie_advance) { ++ ret = aspeed_pcie_active_detect(drm); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "missing or invalid pcie-ep controller device tree entry"); ++ return ret; + } -+ if (i2c_bus->target) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; -+ break; -+ case AST2600_I2CS_WAIT_TX_DMA: -+ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); -+ if (!i2c_bus->target) -+ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ if (i2c_bus->target) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ } -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; -+ break; -+ default: -+ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts, -+ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); -+ -+ /* clear sirq log */ -+ while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) -+ ; -+ break; + } + -+ if (cmd) -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ -+ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+} -+ -+static void ast2600_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) -+{ -+ int target_rx_len = 0; -+ u32 cmd = 0; -+ u8 value; -+ int i; -+ -+ sts &= ~(AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_SADDR_PENDING -+ | AST2600_I2CS_ADDR_NAK_MASK); -+ -+ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; -+ -+ /* Handle i2c target timeout condition */ -+ if (AST2600_I2CS_INACTIVE_TO & sts) { -+ /* Reset time out counter */ -+ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & -+ AST2600_I2CC_AC_TIMING_MASK; -+ -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ /* set rx dma length ,re-send target trigger command and clear irq status */ -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ writel(TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN, -+ i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ return; ++ ret = aspeed_adaptor_detect(drm); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "missing or invalid adaptor controller device tree entry"); ++ return ret; + } + -+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); + /* Sanitize control registers */ + writel(0, priv->base + CRT_CTRL1); + writel(0, priv->base + CRT_CTRL2); +@@ -232,6 +536,23 @@ + return ret; + } + ++ /* install pcie reset detect */ ++ if (of_property_read_bool(np, "pcie-reset-detect") && priv->pcie_advance) { ++ dev_dbg(drm->dev, "hook pcie reset.\n"); + -+ switch (sts) { -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ /* Special watch the host power up / down */ ++ ret = devm_request_irq(drm->dev, platform_get_irq(pdev, 1), aspeed_host_irq_handler, IRQF_SHARED, "aspeed host active", drm); ++ if (ret < 0) { ++ dev_err(drm->dev, "Failed to install HOST active handler\n"); ++ return ret; + } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE_NAK | -+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA | -+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_RX_DONE_NAK | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_STOP: -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ if (sts & AST2600_I2CS_SLAVE_MATCH) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); -+ -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); ++ ret = devm_request_irq(drm->dev, platform_get_irq(pdev, 2), aspeed_host_irq_handler, IRQF_SHARED, "aspeed host deactivate", drm); ++ if (ret < 0) { ++ dev_err(drm->dev, "Failed to install HOST de-active handler\n"); ++ return ret; + } -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ if (sts & AST2600_I2CS_STOP) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; ++ } + -+ /* it is Mw data Mr coming -> it need send tx */ -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA: -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA: -+ /* it should be repeat start read */ -+ if (sts & AST2600_I2CS_SLAVE_MATCH) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); + drm_mode_config_reset(drm); + + return 0; +@@ -239,6 +560,12 @@ + + static void aspeed_gfx_unload(struct drm_device *drm) + { ++ struct aspeed_gfx *priv = drm->dev_private; + -+ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CS_DMA_LEN_STS)); -+ for (i = 0; i < target_rx_len; i++) { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, -+ &i2c_bus->target_dma_buf[i]); -+ } -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA: -+ /* First Start read */ -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, -+ &i2c_bus->target_dma_buf[0]); -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; -+ break; -+ case AST2600_I2CS_WAIT_TX_DMA: -+ /* it should be next start read */ -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, -+ &i2c_bus->target_dma_buf[0]); -+ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; -+ break; -+ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: -+ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: -+ /* it just tx complete */ -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); -+ break; -+ case AST2600_I2CS_STOP: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ /* change the dp setting is coming from host side */ ++ if (priv->dp_support) ++ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, 0); ++ + drm_kms_helper_poll_fini(drm); + } + +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c +--- a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c 2026-09-09 15:51:44.545240686 +0000 +@@ -10,7 +10,19 @@ + + static int aspeed_gfx_get_modes(struct drm_connector *connector) + { +- return drm_add_modes_noedid(connector, 800, 600); ++ struct aspeed_gfx *priv = container_of(connector, struct aspeed_gfx, connector); ++ int mode_count = 0; ++ ++ switch (priv->flags & CLK_MASK) { ++ case CLK_G6: ++ mode_count = drm_add_modes_noedid(connector, 1024, 768); + break; + default: -+ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts, -+ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); ++ mode_count = drm_add_modes_noedid(connector, 800, 600); + break; + } + -+ if (cmd) -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ return mode_count; + } + + static const struct +diff --git a/drivers/hwmon/aspeed-chassis.c b/drivers/hwmon/aspeed-chassis.c +--- a/drivers/hwmon/aspeed-chassis.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/hwmon/aspeed-chassis.c 2026-09-09 15:51:44.149246669 +0000 +@@ -0,0 +1,221 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (C) 2021 ASPEED Technology Inc. ++ * ++ * CHASSIS driver for the Aspeed SoC ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+} ++/* #define USE_INTERRUPTS */ ++/******************************************************************************/ ++union chassis_ctrl_register { ++ u32 value; ++ struct { ++ uint32_t intrusion_status_clear : 1; /*[0]*/ ++ uint32_t intrusion_int_enable : 1; /*[1]*/ ++ uint32_t intrusion_status : 1; /*[2]*/ ++ uint32_t battery_power_good : 1; /*[3]*/ ++ uint32_t chassis_raw_status : 1; /*[4]*/ ++ uint32_t reserved0 : 3; /*[5-7]*/ ++ uint32_t io_power_status_clear : 1; /*[8]*/ ++ uint32_t io_power_int_enable : 1; /*[9]*/ ++ uint32_t core_power_status : 1; /*[10]*/ ++ uint32_t reserved1 : 5; /*[11-15]*/ ++ uint32_t core_power_status_clear : 1; /*[16]*/ ++ uint32_t core_power_int_enable : 1; /*[17]*/ ++ uint32_t io_power_status : 1; /*[18]*/ ++ uint32_t reserved2 : 13; /*[19-31]*/ ++ } fields; ++}; + -+static void ast2600_i2c_target_packet_buff_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++struct aspeed_chassis { ++ struct device *dev; ++ void __iomem *base; ++ int irq; ++ /* for hwmon */ ++ const struct attribute_group *groups[2]; ++}; ++ ++static ssize_t ++intrusion_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+ int target_rx_len = 0; -+ u32 cmd = 0; -+ u8 value; -+ int i; ++ unsigned long val; ++ struct aspeed_chassis *chassis = dev_get_drvdata(dev); ++ union chassis_ctrl_register chassis_ctrl; + -+ /* due to controller target share same buffer, so need force the master stop not issue */ -+ if (readl(i2c_bus->reg_base + AST2600_I2CM_CMD_STS) & GENMASK(15, 0)) { -+ writel(0, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); -+ i2c_bus->cmd_err = -EBUSY; -+ writel(0, i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ complete(&i2c_bus->cmd_complete); -+ } ++ if (kstrtoul(buf, 10, &val) < 0 || val != 0) ++ return -EINVAL; + -+ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; ++ chassis_ctrl.value = readl(chassis->base); ++ chassis_ctrl.fields.intrusion_status_clear = 1; ++ writel(chassis_ctrl.value, chassis->base); ++ chassis_ctrl.fields.intrusion_status_clear = 0; ++ writel(chassis_ctrl.value, chassis->base); ++ return count; ++} + -+ /* Handle i2c target timeout condition */ -+ if (AST2600_I2CS_INACTIVE_TO & sts) { -+ /* Reset time out counter */ -+ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & -+ AST2600_I2CC_AC_TIMING_MASK; ++static ssize_t intrusion_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int index = sensor_attr->index; ++ struct aspeed_chassis *chassis = dev_get_drvdata(dev); ++ union chassis_ctrl_register chassis_ctrl; ++ u8 ret; + -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ /* Re-send target trigger command and clear irq */ -+ writel(TARGET_TRIGGER_CMD, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target_operate = 0; -+ return; ++ chassis_ctrl.value = readl(chassis->base); ++ ++ switch (index) { ++ case 0: ++ ret = chassis_ctrl.fields.core_power_status; ++ break; ++ case 1: ++ ret = chassis_ctrl.fields.io_power_status; ++ break; ++ case 2: ++ ret = chassis_ctrl.fields.intrusion_status; ++ break; + } + -+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); ++ return sprintf(buf, "%d\n", ret); ++} + -+ if (sts & AST2600_I2CS_SLAVE_MATCH) -+ i2c_bus->target_operate = 1; ++static SENSOR_DEVICE_ATTR_RO(core_power, intrusion, 0); ++static SENSOR_DEVICE_ATTR_RO(io_power, intrusion, 1); ++static SENSOR_DEVICE_ATTR_RW(intrusion0_alarm, intrusion, 2); + -+ switch (sts) { -+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_SLAVE_PENDING | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ case AST2600_I2CS_SLAVE_PENDING | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ fallthrough; -+ case AST2600_I2CS_SLAVE_PENDING | -+ AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); -+ cmd = TARGET_TRIGGER_CMD; -+ if (sts & AST2600_I2CS_RX_DONE) { -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ } -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_RX_BUFF_EN) -+ cmd = 0; -+ else -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN; ++static struct attribute *intrusion_dev_attrs[] = { ++ &sensor_dev_attr_core_power.dev_attr.attr, ++ &sensor_dev_attr_io_power.dev_attr.attr, ++ &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, NULL ++}; + -+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size), -+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ break; -+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_RX_DONE: -+ cmd = TARGET_TRIGGER_CMD; -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ cmd |= AST2600_I2CS_RX_BUFF_EN; -+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size), -+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ break; -+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA | -+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ cmd = TARGET_TRIGGER_CMD; -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ cmd |= AST2600_I2CS_RX_BUFF_EN; -+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size), -+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ break; -+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ cmd = TARGET_TRIGGER_CMD; -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ /* workaround for avoid next start with len != 0 */ -+ writel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ break; -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: -+ cmd = TARGET_TRIGGER_CMD; -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ /* workaround for avoid next start with len != 0 */ -+ writel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ break; -+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE | -+ AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_STOP: -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); -+ writeb(value, i2c_bus->buf_base); -+ break; -+ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); -+ writeb(value, i2c_bus->buf_base); -+ writel(AST2600_I2CC_SET_TX_BUF_LEN(1), -+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN; -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE: -+ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE: -+ case AST2600_I2CS_WAIT_TX_DMA: -+ /* it should be repeat start read */ -+ if (sts & AST2600_I2CS_SLAVE_MATCH) -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++static const struct attribute_group intrusion_dev_group = { ++ .attrs = intrusion_dev_attrs, ++ .is_visible = NULL, ++}; + -+ if (sts & AST2600_I2CS_RX_DONE) { -+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < target_rx_len; i++) { -+ value = readb(i2c_bus->buf_base + 0x10 + i); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); -+ } else { -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &value); -+ } -+ writeb(value, i2c_bus->buf_base); -+ writel(AST2600_I2CC_SET_TX_BUF_LEN(1), -+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN; -+ break; -+ /* workaround : trigger the cmd twice to fix next state keep 1000000 */ -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); -+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN; -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ break; -+ /* the pending slave needs to be cleared with TX_NAK and STOP here */ -+ /* other flags will be handled in the next irq callback */ -+ /* the slave index will be updated when the slave match occurs */ -+ /* use the pervious idx to do the slave stop event */ -+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: -+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | -+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: -+ cmd = TARGET_TRIGGER_CMD; -+ i2c_bus->target = i2c_bus->multi_target[i2c_bus->previous_idx]; -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ i2c_bus->target_operate = 0; -+ break; -+ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: -+ case AST2600_I2CS_STOP: -+ cmd = TARGET_TRIGGER_CMD; -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ break; -+ default: -+ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts, -+ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); -+ break; ++#ifdef USE_INTERRUPTS ++static void aspeed_chassis_status_check(struct aspeed_chassis *chassis) ++{ ++ union chassis_ctrl_register chassis_ctrl; ++ ++ chassis_ctrl.value = readl(chassis->base); ++ if (chassis_ctrl.fields.intrusion_status) { ++ dev_info(chassis->dev, "CHASI# pin has been pulled low"); ++ chassis_ctrl.fields.intrusion_status_clear = 1; ++ writel(chassis_ctrl.value, chassis->base); ++ chassis_ctrl.fields.intrusion_status_clear = 0; ++ writel(chassis_ctrl.value, chassis->base); + } + -+ if (cmd) -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ if (chassis_ctrl.fields.core_power_status) { ++ dev_info(chassis->dev, "Core power has been pulled low"); ++ chassis_ctrl.fields.core_power_status_clear = 1; ++ writel(chassis_ctrl.value, chassis->base); ++ chassis_ctrl.fields.core_power_status_clear = 0; ++ writel(chassis_ctrl.value, chassis->base); ++ } + -+ if ((sts & AST2600_I2CS_STOP) && !(sts & AST2600_I2CS_SLAVE_PENDING)) -+ i2c_bus->target_operate = 0; -+ else -+ i2c_bus->previous_idx = AST2600_I2CS_GET_TARGET(sts); ++ if (chassis_ctrl.fields.io_power_status) { ++ dev_info(chassis->dev, "IO power has been pulled low"); ++ chassis_ctrl.fields.io_power_status_clear = 1; ++ writel(chassis_ctrl.value, chassis->base); ++ chassis_ctrl.fields.io_power_status_clear = 0; ++ writel(chassis_ctrl.value, chassis->base); ++ } +} + -+static void ast2600_i2c_target_byte_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++static irqreturn_t aspeed_chassis_isr(int this_irq, void *dev_id) +{ -+ u32 i2c_buff = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ u32 cmd = AST2600_I2CS_ACTIVE_ALL; -+ u8 byte_data; -+ u8 value; ++ struct aspeed_chassis *chassis = dev_id; + -+ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; ++ aspeed_chassis_status_check(chassis); ++ return IRQ_HANDLED; ++} ++#endif + -+ /* Handle i2c target timeout condition */ -+ if (AST2600_I2CS_INACTIVE_TO & sts) { -+ /* Reset time out counter */ -+ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & -+ AST2600_I2CC_AC_TIMING_MASK; ++static void aspeed_chassis_int_ctrl(struct aspeed_chassis *chassis, bool ctrl) ++{ ++ union chassis_ctrl_register chassis_ctrl; + -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); -+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); -+ /* Re-send target trigger command and clear irq */ -+ writel(AST2600_I2CS_ACTIVE_ALL, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ writel(sts, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ return; -+ } ++ chassis_ctrl.value = readl(chassis->base); ++ chassis_ctrl.fields.intrusion_int_enable = ctrl; ++ chassis_ctrl.fields.io_power_int_enable = ctrl; ++ chassis_ctrl.fields.core_power_int_enable = ctrl; ++ writel(chassis_ctrl.value, chassis->base); ++} + -+ sts &= ~(AST2600_I2CS_ADDR_INDICATE_MASK); ++static const struct of_device_id aspeed_chassis_of_table[] = { ++ { .compatible = "aspeed,ast2600-chassis" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, aspeed_chassis_of_table); + -+ switch (sts) { -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); -+ /* first address match is address */ -+ byte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff); -+ break; -+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: -+ byte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &byte_data); -+ break; -+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA: -+ cmd |= AST2600_I2CS_TX_CMD; -+ byte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff); -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &byte_data); -+ writel(byte_data, i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ break; -+ case AST2600_I2CS_TX_ACK | AST2600_I2CS_WAIT_TX_DMA: -+ cmd |= AST2600_I2CS_TX_CMD; -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &byte_data); -+ writel(byte_data, i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ break; -+ case AST2600_I2CS_STOP: -+ case AST2600_I2CS_STOP | AST2600_I2CS_TX_NAK: -+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); -+ break; -+ default: -+ dev_dbg(i2c_bus->dev, "unhandled pkt isr %x\n", sts); -+ break; ++static int aspeed_chassis_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct aspeed_chassis *priv; ++ struct device *hwmon; ++ int __maybe_unused ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++#ifdef USE_INTERRUPTS ++ priv->irq = platform_get_irq(pdev, 0); ++ if (priv->irq < 0) { ++ dev_err(dev, "no irq specified\n"); ++ return -ENOENT; + } -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ writel(sts, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+} + -+static int ast2600_i2c_target_irq(struct ast2600_i2c_bus *i2c_bus) -+{ -+ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CS_IER); -+ u32 isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ ret = devm_request_irq(dev, priv->irq, aspeed_chassis_isr, 0, ++ dev_name(dev), priv); ++ if (ret) { ++ dev_err(dev, "Chassis Unable to get IRQ"); ++ return ret; ++ } ++ aspeed_chassis_int_ctrl(priv, true); ++#else ++ aspeed_chassis_int_ctrl(priv, false); ++#endif + -+ if (!(isr & ier)) -+ return 0; ++ priv->groups[0] = &intrusion_dev_group; ++ priv->groups[1] = NULL; + -+ /* -+ * Target interrupt coming after Controller package done -+ * So need handle controller first. -+ */ -+ if (readl(i2c_bus->reg_base + AST2600_I2CM_ISR) & AST2600_I2CM_PKT_DONE) -+ return 0; ++ hwmon = devm_hwmon_device_register_with_groups(dev, "aspeed_chassis", ++ priv, priv->groups); + -+ isr &= ~(AST2600_I2CS_ADDR_MASK); ++ return PTR_ERR_OR_ZERO(hwmon); ++} + -+ if (AST2600_I2CS_PKT_DONE & isr) { -+ if (i2c_bus->mode == DMA_MODE) { -+ if (i2c_bus->version == AST2700) -+ ast2700_i2c_target_packet_dma_irq(i2c_bus, isr); -+ else -+ ast2600_i2c_target_packet_dma_irq(i2c_bus, isr); -+ } else { -+ ast2600_i2c_target_packet_buff_irq(i2c_bus, isr); -+ } -+ } else { -+ ast2600_i2c_target_byte_irq(i2c_bus, isr); -+ } ++static struct platform_driver aspeed_chassis_driver = { ++ .probe = aspeed_chassis_probe, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_chassis_of_table, ++ }, ++}; + -+ return 1; ++module_platform_driver(aspeed_chassis_driver); ++ ++MODULE_AUTHOR("Billy Tsai"); ++MODULE_DESCRIPTION("ASPEED CHASSIS Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c +--- a/drivers/hwmon/aspeed-g6-pwm-tach.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/hwmon/aspeed-g6-pwm-tach.c 2026-09-09 15:51:44.156246564 +0000 +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -137,7 +138,7 @@ + struct reset_control *reset; + unsigned long clk_rate; + bool tach_present[TACH_ASPEED_NR_TACHS]; +- u32 tach_divisor; ++ u32 tach_divisor[TACH_ASPEED_NR_TACHS]; + }; + + static inline struct aspeed_pwm_tach_data * +@@ -282,12 +283,14 @@ + priv->base + TACH_ASPEED_CTRL(tach_ch)); + } + +-static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, u32 tach_val) ++static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, ++ u32 tach_val, u8 fan_tach_ch) + { + u64 rpm; + u32 tach_div; + +- tach_div = tach_val * priv->tach_divisor * DEFAULT_FAN_PULSE_PR; ++ tach_div = tach_val * priv->tach_divisor[fan_tach_ch] * ++ DEFAULT_FAN_PULSE_PR; + + dev_dbg(priv->dev, "clk %ld, tach_val %d , tach_div %d\n", + priv->clk_rate, tach_val, tach_div); +@@ -308,7 +311,7 @@ + if (!(val & TACH_ASPEED_FULL_MEASUREMENT)) + return 0; + val = FIELD_GET(TACH_ASPEED_VALUE_MASK, val); +- return aspeed_tach_val_to_rpm(priv, val); ++ return aspeed_tach_val_to_rpm(priv, val, fan_tach_ch); + } + + static int aspeed_tach_hwmon_read(struct device *dev, +@@ -345,11 +348,11 @@ + if (!is_power_of_2(val) || (ilog2(val) % 2) || + DIV_TO_REG(val) > 0xb) + return -EINVAL; +- priv->tach_divisor = val; ++ priv->tach_divisor[channel] = val; + reg_val = readl(priv->base + TACH_ASPEED_CTRL(channel)); + reg_val &= ~TACH_ASPEED_CLK_DIV_T_MASK; + reg_val |= FIELD_PREP(TACH_ASPEED_CLK_DIV_T_MASK, +- DIV_TO_REG(priv->tach_divisor)); ++ DIV_TO_REG(priv->tach_divisor[channel])); + writel(reg_val, priv->base + TACH_ASPEED_CTRL(channel)); + break; + default: +@@ -407,7 +410,7 @@ + for (index = 0; index < count; index++) { + ch = tach_ch[index]; + priv->tach_present[ch] = true; +- priv->tach_divisor = DEFAULT_TACH_DIV; ++ priv->tach_divisor[ch] = DEFAULT_TACH_DIV; + + val = readl(priv->base + TACH_ASPEED_CTRL(ch)); + val &= ~(TACH_ASPEED_INVERS_LIMIT | TACH_ASPEED_DEBOUNCE_MASK | +@@ -416,7 +419,7 @@ + val |= (DEBOUNCE_3_CLK << TACH_ASPEED_DEBOUNCE_BIT) | + F2F_EDGES | + FIELD_PREP(TACH_ASPEED_CLK_DIV_T_MASK, +- DIV_TO_REG(priv->tach_divisor)); ++ DIV_TO_REG(priv->tach_divisor[ch])); + writel(val, priv->base + TACH_ASPEED_CTRL(ch)); + + aspeed_tach_ch_enable(priv, ch, true); +@@ -452,6 +455,50 @@ + reset_control_assert(rst); + } + ++static void aspeed_pwm_set_wdt_reload(struct pwm_chip *chip, ++ struct pwm_device *pwm, ++ u64 reload_duty_cycle) ++{ ++ struct aspeed_pwm_tach_data *priv = aspeed_pwm_chip_to_data(chip); ++ u32 hwpwm = pwm->hwpwm, val; ++ ++ val = readl(priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); ++ val &= ~PWM_ASPEED_DUTY_CYCLE_POINT_AS_WDT; ++ val |= FIELD_PREP(PWM_ASPEED_DUTY_CYCLE_POINT_AS_WDT, ++ reload_duty_cycle); ++ writel(val, priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); ++ ++ val = readl(priv->base + PWM_ASPEED_CTRL(hwpwm)); ++ val |= PWM_ASPEED_CTRL_DUTY_LOAD_AS_WDT_ENABLE; ++ writel(val, priv->base + PWM_ASPEED_CTRL(hwpwm)); +} -+#endif + -+static int ast2600_i2c_setup_dma_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) ++static struct pwm_device * ++aspeed_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; -+ int ret; ++ struct pwm_device *pwm; + -+ cmd |= AST2600_I2CM_PKT_EN; ++ /* period in the second cell and flags in the third cell are optional */ ++ if (args->args_count < 1) ++ return ERR_PTR(-EINVAL); + -+ if (xfer_len > AST2600_I2C_DMA_SIZE) -+ xfer_len = AST2600_I2C_DMA_SIZE; -+ else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) -+ cmd |= AST2600_I2CM_STOP_CMD; ++ pwm = pwm_request_from_chip(chip, args->args[0], NULL); ++ if (IS_ERR(pwm)) ++ return pwm; + -+ if (cmd & AST2600_I2CM_START_CMD) { -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); -+ if (xfer_len) { -+ i2c_bus->controller_safe_buf = i2c_get_dma_safe_msg_buf(msg, 1); -+ if (!i2c_bus->controller_safe_buf) -+ return -ENOMEM; -+ i2c_bus->controller_dma_addr = -+ dma_map_single(i2c_bus->dev, i2c_bus->controller_safe_buf, -+ msg->len, DMA_TO_DEVICE); -+ ret = dma_mapping_error(i2c_bus->dev, i2c_bus->controller_dma_addr); -+ if (ret) { -+ i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, false); -+ i2c_bus->controller_safe_buf = NULL; -+ return ret; -+ } -+ } -+ } ++ if (args->args_count > 1) ++ pwm->args.period = args->args[1]; + -+ if (xfer_len) { -+ cmd |= AST2600_I2CM_TX_DMA_EN | AST2600_I2CM_TX_CMD; -+ writel(AST2600_I2CM_SET_TX_DMA_LEN(xfer_len - 1), -+ i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); -+ writel(lower_32_bits(i2c_bus->controller_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CM_TX_DMA); -+ writel(upper_32_bits(i2c_bus->controller_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CM_TX_DMA_H); -+ } ++ pwm->args.polarity = PWM_POLARITY_NORMAL; ++ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) ++ pwm->args.polarity = PWM_POLARITY_INVERSED; + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ if (args->args_count > 3 && args->args[3] < U8_MAX) ++ aspeed_pwm_set_wdt_reload(chip, pwm, args->args[3]); + -+ return 0; ++ return pwm; +} + -+static int ast2600_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; -+ u32 wbuf_dword; -+ int i; + static int aspeed_pwm_tach_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev, *hwmon; +@@ -493,6 +540,8 @@ + pwmchip_set_drvdata(chip, priv); + chip->ops = &aspeed_pwm_ops; + ++ chip->of_xlate = aspeed_pwm_xlate; + -+ cmd |= AST2600_I2CM_PKT_EN; + ret = devm_pwmchip_add(dev, chip); + if (ret) + return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); +@@ -521,6 +570,9 @@ + { + .compatible = "aspeed,ast2600-pwm-tach", + }, ++ { ++ .compatible = "aspeed,ast2700-pwm-tach", ++ }, + {}, + }; + MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); +diff --git a/drivers/i2c/busses/i2c-ast2600.c b/drivers/i2c/busses/i2c-ast2600.c +--- a/drivers/i2c/busses/i2c-ast2600.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/i2c/busses/i2c-ast2600.c 2026-09-09 15:51:44.101247395 +0000 +@@ -0,0 +1,3134 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * ASPEED AST2600 new register set I2C controller driver ++ * ++ * Copyright (C) 2023 ASPEED Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ if (xfer_len > i2c_bus->buf_size) -+ xfer_len = i2c_bus->buf_size; -+ else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) -+ cmd |= AST2600_I2CM_STOP_CMD; ++#define AST2600_I2CG_ISR 0x00 ++#define AST2600_I2CG_SLAVE_ISR 0x04 ++#define AST2600_I2CG_OWNER 0x08 ++#define AST2600_I2CG_CTRL 0x0C ++#define AST2600_I2CG_CLK_DIV_CTRL 0x10 + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++#define AST2600_I2CG_SLAVE_PKT_NAK BIT(4) ++#define AST2600_I2CG_M_S_SEPARATE_INTR BIT(3) ++#define AST2600_I2CG_CTRL_NEW_REG BIT(2) ++#define AST2600_I2CG_CTRL_NEW_CLK_DIV BIT(1) ++#define AST2600_GLOBAL_INIT \ ++ (AST2600_I2CG_CTRL_NEW_REG | AST2600_I2CG_CTRL_NEW_CLK_DIV) ++/* ++ * APB clk : 100Mhz ++ * div : scl : baseclk [APB/((div/2) + 1)] : tBuf [1/bclk * 16] ++ * I2CG10[31:24] base clk4 for i2c auto recovery timeout counter (0xC6) ++ * I2CG10[23:16] base clk3 for Standard-mode (100Khz) min tBuf 4.7us ++ * 0x3c : 100.8Khz : 3.225Mhz : 4.96us ++ * 0x3d : 99.2Khz : 3.174Mhz : 5.04us ++ * 0x3e : 97.65Khz : 3.125Mhz : 5.12us ++ * 0x40 : 97.75Khz : 3.03Mhz : 5.28us ++ * 0x41 : 99.5Khz : 2.98Mhz : 5.36us (default) ++ * I2CG10[15:8] base clk2 for Fast-mode (400Khz) min tBuf 1.3us ++ * 0x12 : 400Khz : 10Mhz : 1.6us ++ * I2CG10[7:0] base clk1 for Fast-mode Plus (1Mhz) min tBuf 0.5us ++ * 0x08 : 1Mhz : 20Mhz : 0.8us ++ */ ++#define AST2600_I2CCG_DIV_CTRL 0xC6411208 ++#define AST2700_I2CCG_DIV_CTRL 0xC6220904 ++#define AST2700_MIN_AC_TIMING 12000 ++#define AST_DEFAULT_AC_TIMING 100000 + -+ if (xfer_len) { -+ cmd |= AST2600_I2CM_TX_BUFF_EN | AST2600_I2CM_TX_CMD; -+ /* -+ * The controller's buffer register supports dword writes only. -+ * Therefore, write dwords to the buffer register in a 4-byte aligned, -+ * and write the remaining unaligned data at the end. -+ */ -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -+ return -ENOMEM; -+ for (i = 0; i < xfer_len; i += 4) { -+ int xfer_cnt = i2c_bus->controller_xfer_cnt + i; ++/* 0x00 : I2CC Controller/Target Function Control Register */ ++#define AST2600_I2CC_FUN_CTRL 0x00 ++#define AST2600_I2CC_SLAVE_ADDR_RX_EN BIT(20) ++#define AST2600_I2CC_MASTER_RETRY_MASK GENMASK(19, 18) ++#define AST2600_I2CC_MASTER_RETRY(x) (((x) & GENMASK(1, 0)) << 18) ++#define AST2600_I2CC_BUS_AUTO_RELEASE BIT(17) ++#define AST2600_I2CC_M_SDA_LOCK_EN BIT(16) ++#define AST2600_I2CC_MULTI_MASTER_DIS BIT(15) ++#define AST2600_I2CC_M_SCL_DRIVE_EN BIT(14) ++#define AST2600_I2CC_MSB_STS BIT(9) ++#define AST2600_I2CC_SDA_DRIVE_1T_EN BIT(8) ++#define AST2600_I2CC_M_SDA_DRIVE_1T_EN BIT(7) ++#define AST2600_I2CC_M_HIGH_SPEED_EN BIT(6) ++#define AST2700_I2CC_MANUAL_DEBOUNCE GENMASK(5, 4) ++/* reserver 5 : 2 */ ++#define AST2600_I2CC_SLAVE_EN BIT(1) ++#define AST2600_I2CC_MASTER_EN BIT(0) + -+ switch (min(xfer_len - i, 4) % 4) { -+ case 1: -+ wbuf_dword = msg->buf[xfer_cnt]; -+ break; -+ case 2: -+ wbuf_dword = get_unaligned_le16(&msg->buf[xfer_cnt]); -+ break; -+ case 3: -+ wbuf_dword = get_unaligned_le24(&msg->buf[xfer_cnt]); -+ break; -+ default: -+ wbuf_dword = get_unaligned_le32(&msg->buf[xfer_cnt]); -+ break; -+ } -+ writel(wbuf_dword, i2c_bus->buf_base + i); -+ } -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -+ return -ENOMEM; -+ writel(AST2600_I2CC_SET_TX_BUF_LEN(xfer_len), -+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); -+ } ++/* 0x04 : I2CC Controller/Target Clock and AC Timing Control Register #1 */ ++#define AST2600_I2CC_AC_TIMING 0x04 ++#define AST2600_I2CC_TTIMEOUT(x) (((x) & GENMASK(4, 0)) << 24) ++#define AST2700_I2CC_TTIMEOUT(x) (((x) & GENMASK(5, 0)) << 24) ++#define AST2600_I2CC_TCKHIGHMIN(x) (((x) & GENMASK(3, 0)) << 20) ++#define AST2600_I2CC_TCKHIGH(x) (((x) & GENMASK(3, 0)) << 16) ++#define AST2600_I2CC_TCKLOW(x) (((x) & GENMASK(3, 0)) << 12) ++#define AST2600_I2CC_THDDAT(x) (((x) & GENMASK(1, 0)) << 10) ++#define AST2600_I2CC_TOUTBASECLK(x) (((x) & GENMASK(1, 0)) << 8) ++#define AST2600_I2CC_TBASECLK(x) ((x) & GENMASK(3, 0)) ++#define AST2600_I2CC_AC_TIMING_MASK GENMASK(23, 0) + -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -+ return -ENOMEM; ++/* 0x08 : I2CC Controller/Target Transmit/Receive Byte Buffer Register */ ++#define AST2600_I2CC_STS_AND_BUFF 0x08 ++#define AST2600_I2CC_TX_DIR_MASK GENMASK(31, 29) ++#define AST2600_I2CC_SDA_OE BIT(28) ++#define AST2600_I2CC_SDA_O BIT(27) ++#define AST2600_I2CC_SCL_OE BIT(26) ++#define AST2600_I2CC_SCL_O BIT(25) ++ ++#define AST2600_I2CC_SCL_LINE_STS BIT(18) ++#define AST2600_I2CC_SDA_LINE_STS BIT(17) ++#define AST2600_I2CC_BUS_BUSY_STS BIT(16) ++ ++#define AST2600_I2CC_GET_RX_BUFF(x) (((x) >> 8) & GENMASK(7, 0)) ++ ++/* 0x0C : I2CC Controller/Target Pool Buffer Control Register */ ++#define AST2600_I2CC_BUFF_CTRL 0x0C ++#define AST2600_I2CC_GET_RX_BUF_LEN(x) (((x) & GENMASK(29, 24)) >> 24) ++#define AST2600_I2CC_SET_RX_BUF_LEN(x) (((((x) - 1) & GENMASK(4, 0)) << 16) | BIT(0)) ++#define AST2600_I2CC_SET_TX_BUF_LEN(x) (((((x) - 1) & GENMASK(4, 0)) << 8) | BIT(0)) ++#define AST2600_I2CC_GET_TX_BUF_LEN(x) ((((x) & GENMASK(12, 8)) >> 8) + 1) ++ ++/* 0x10 : I2CM Controller Interrupt Control Register */ ++#define AST2600_I2CM_IER 0x10 ++/* 0x14 : I2CM Controller Interrupt Status Register : WC */ ++#define AST2600_I2CM_ISR 0x14 ++ ++#define AST2600_I2CM_ISR_MASK GENMASK(31, 21) ++#define AST2600_I2CM_SW_ISR_MASK GENMASK(31, 19) ++ ++#define AST2600_I2CM_PKT_TIMEOUT BIT(18) ++#define AST2600_I2CM_PKT_ERROR BIT(17) ++#define AST2600_I2CM_PKT_DONE BIT(16) ++ ++#define AST2600_I2CM_BUS_RECOVER_FAIL BIT(15) ++#define AST2600_I2CM_SDA_DL_TO BIT(14) ++#define AST2600_I2CM_BUS_RECOVER BIT(13) ++#define AST2600_I2CM_SMBUS_ALERT BIT(12) ++#define AST2700_I2CM_ABNORMAL_ACTION BIT(8) ++ ++#define AST2600_I2CM_SCL_LOW_TO BIT(6) ++#define AST2600_I2CM_ABNORMAL BIT(5) ++#define AST2600_I2CM_NORMAL_STOP BIT(4) ++#define AST2600_I2CM_ARBIT_LOSS BIT(3) ++#define AST2600_I2CM_RX_DONE BIT(2) ++#define AST2600_I2CM_TX_NAK BIT(1) ++#define AST2600_I2CM_TX_ACK BIT(0) ++ ++/* 0x18 : I2CM Controller Command/Status Register */ ++#define AST2600_I2CM_CMD_STS 0x18 ++#define AST2600_I2CM_PKT_ADDR(x) (((x) & GENMASK(6, 0)) << 24) ++#define AST2600_I2CM_PKT_EN BIT(16) ++#define AST2600_I2CM_SDA_OE_OUT_DIR BIT(15) ++#define AST2600_I2CM_SDA_O_OUT_DIR BIT(14) ++#define AST2600_I2CM_SCL_OE_OUT_DIR BIT(13) ++#define AST2600_I2CM_SCL_O_OUT_DIR BIT(12) ++#define AST2600_I2CM_RECOVER_CMD_EN BIT(11) ++ ++#define AST2600_I2CM_RX_DMA_EN BIT(9) ++#define AST2600_I2CM_TX_DMA_EN BIT(8) ++/* Command Bit */ ++#define AST2600_I2CM_RX_BUFF_EN BIT(7) ++#define AST2600_I2CM_TX_BUFF_EN BIT(6) ++#define AST2600_I2CM_STOP_CMD BIT(5) ++#define AST2600_I2CM_RX_CMD_LAST BIT(4) ++#define AST2600_I2CM_RX_CMD BIT(3) + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++#define AST2600_I2CM_TX_CMD BIT(1) ++#define AST2600_I2CM_START_CMD BIT(0) + -+ return 0; -+} ++/* 0x1C : I2CM Controller DMA Transfer Length Register */ ++#define AST2600_I2CM_DMA_LEN 0x1C ++/* Controller Tx Rx support length 1 ~ 4096 */ ++#define AST2600_I2CM_SET_RX_DMA_LEN(x) ((((x) & GENMASK(11, 0)) << 16) | BIT(31)) ++#define AST2600_I2CM_SET_TX_DMA_LEN(x) (((x) & GENMASK(11, 0)) | BIT(15)) + -+static int ast2600_i2c_setup_byte_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len; ++/* 0x20 : I2CS Target Interrupt Control Register */ ++#define AST2600_I2CS_IER 0x20 ++/* 0x24 : I2CS Target Interrupt Status Register */ ++#define AST2600_I2CS_ISR 0x24 + -+ xfer_len = msg->len - i2c_bus->controller_xfer_cnt; ++#define AST2600_I2CS_ADDR_INDICATE_MASK GENMASK(31, 30) ++#define AST2600_I2CS_SLAVE_PENDING BIT(29) ++#define AST2600_I2CS_SADDR_PENDING BIT(28) + -+ cmd |= AST2600_I2CM_PKT_EN; ++#define AST2600_I2CS_WAIT_TX_DMA BIT(25) ++#define AST2600_I2CS_WAIT_RX_DMA BIT(24) + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++#define AST2600_I2CS_ADDR3_NAK BIT(22) ++#define AST2600_I2CS_ADDR2_NAK BIT(21) ++#define AST2600_I2CS_ADDR1_NAK BIT(20) + -+ if ((i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) && -+ xfer_len == 1) -+ cmd |= AST2600_I2CM_STOP_CMD; ++#define AST2600_I2CS_ADDR_NAK_MASK GENMASK(22, 20) ++#define AST2600_I2CS_ADDR_MASK GENMASK(19, 18) ++#define AST2600_I2CS_GET_TARGET(x) (((x) >> 30) & 0x3) ++#define AST2600_I2CS_PKT_ERROR BIT(17) ++#define AST2600_I2CS_PKT_DONE BIT(16) ++#define AST2600_I2CS_INACTIVE_TO BIT(15) + -+ if (xfer_len) { -+ cmd |= AST2600_I2CM_TX_CMD; -+ writel(msg->buf[i2c_bus->controller_xfer_cnt], -+ i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ } ++#define AST2600_I2CS_SLAVE_MATCH BIT(7) ++#define AST2600_I2CS_ABNOR_STOP BIT(5) ++#define AST2600_I2CS_STOP BIT(4) ++#define AST2600_I2CS_RX_DONE_NAK BIT(3) ++#define AST2600_I2CS_RX_DONE BIT(2) ++#define AST2600_I2CS_TX_NAK BIT(1) ++#define AST2600_I2CS_TX_ACK BIT(0) + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++/* 0x28 : I2CS Target CMD/Status Register */ ++#define AST2600_I2CS_CMD_STS 0x28 ++#define AST2600_I2CS_ACTIVE_ALL GENMASK(18, 17) ++#define AST2600_I2CS_PKT_MODE_EN BIT(16) ++#define AST2600_I2CS_AUTO_NAK_NOADDR BIT(15) ++#define AST2600_I2CS_AUTO_NAK_EN BIT(14) + -+ return 0; -+} ++#define AST2600_I2CS_ALT_EN BIT(10) ++#define AST2600_I2CS_RX_DMA_EN BIT(9) ++#define AST2600_I2CS_TX_DMA_EN BIT(8) ++#define AST2600_I2CS_RX_BUFF_EN BIT(7) ++#define AST2600_I2CS_TX_BUFF_EN BIT(6) ++#define AST2600_I2CS_RX_CMD_LAST BIT(4) + -+static int ast2600_i2c_setup_dma_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; -+ int ret; ++#define AST2600_I2CS_TX_CMD BIT(2) + -+ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_DMA_EN | AST2600_I2CM_RX_CMD; ++#define AST2600_I2CS_DMA_LEN 0x2C + -+ if (msg->flags & I2C_M_RECV_LEN) { -+ dev_dbg(i2c_bus->dev, "smbus read\n"); -+ xfer_len = 1; -+ } else if (xfer_len > AST2600_I2C_DMA_SIZE) { -+ xfer_len = AST2600_I2C_DMA_SIZE; -+ } else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) { -+ cmd |= CONTROLLER_TRIGGER_LAST_STOP; -+ } ++/* Target Tx Rx support length 1 ~ 4096 */ ++#define AST2600_I2CS_SET_RX_DMA_LEN(x) (((((x) - 1) & GENMASK(11, 0)) << 16) | BIT(31)) ++#define AST2600_I2CS_SET_TX_DMA_LEN(x) ((((x) - 1) & GENMASK(11, 0)) | BIT(15)) + -+ writel(AST2600_I2CM_SET_RX_DMA_LEN(xfer_len - 1), i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); ++/* I2CM Controller DMA Tx Buffer Register */ ++#define AST2600_I2CM_TX_DMA 0x30 ++/* I2CM Controller DMA Rx Buffer Register */ ++#define AST2600_I2CM_RX_DMA 0x34 ++/* I2CS Target DMA Tx Buffer Register */ ++#define AST2600_I2CS_TX_DMA 0x38 ++/* I2CS Target DMA Rx Buffer Register */ ++#define AST2600_I2CS_RX_DMA 0x3C + -+ if (cmd & AST2600_I2CM_START_CMD) { -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); -+ i2c_bus->controller_safe_buf = i2c_get_dma_safe_msg_buf(msg, 1); -+ if (!i2c_bus->controller_safe_buf) -+ return -ENOMEM; -+ if (msg->flags & I2C_M_RECV_LEN) -+ i2c_bus->controller_dma_addr = -+ dma_map_single(i2c_bus->dev, i2c_bus->controller_safe_buf, -+ I2C_SMBUS_BLOCK_MAX + 3, DMA_FROM_DEVICE); -+ else -+ i2c_bus->controller_dma_addr = -+ dma_map_single(i2c_bus->dev, i2c_bus->controller_safe_buf, -+ msg->len, DMA_FROM_DEVICE); -+ ret = dma_mapping_error(i2c_bus->dev, i2c_bus->controller_dma_addr); -+ if (ret) { -+ i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, false); -+ i2c_bus->controller_safe_buf = NULL; -+ return -ENOMEM; -+ } -+ } ++/* I2CM Controller DMA Rx Buffer High part Register */ ++#define AST2600_I2CM_TX_DMA_H 0x60 ++/* I2CM Controller DMA Rx Buffer High part Register */ ++#define AST2600_I2CM_RX_DMA_H 0x64 ++/* I2CS Target DMA Tx Buffer High part Register */ ++#define AST2600_I2CS_TX_DMA_H 0x68 ++/* I2CS Target DMA Rx Buffer High part Register */ ++#define AST2600_I2CS_RX_DMA_H 0x6C + -+ writel(lower_32_bits(i2c_bus->controller_dma_addr + -+ i2c_bus->controller_xfer_cnt), -+ i2c_bus->reg_base + AST2600_I2CM_RX_DMA); -+ writel(upper_32_bits(i2c_bus->controller_dma_addr + -+ i2c_bus->controller_xfer_cnt), -+ i2c_bus->reg_base + AST2600_I2CM_RX_DMA_H); ++#define AST2600_I2CS_ADDR_CTRL 0x40 + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++#define AST2600_I2CS_ADDR3_MASK GENMASK(22, 16) ++#define AST2600_I2CS_ADDR2_MASK GENMASK(14, 8) ++#define AST2600_I2CS_ADDR1_MASK GENMASK(6, 0) + -+ return 0; -+} ++#define AST2600_I2CM_DMA_LEN_STS 0x48 ++#define AST2600_I2CS_DMA_LEN_STS 0x4C + -+static int ast2600_i2c_setup_buff_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; ++#define AST2600_I2C_GET_TX_DMA_LEN(x) ((x) & GENMASK(12, 0)) ++#define AST2600_I2C_GET_RX_DMA_LEN(x) (((x) & GENMASK(28, 16)) >> 16) + -+ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_BUFF_EN | AST2600_I2CM_RX_CMD; ++/* 0x40 : Target Device Address Register */ ++#define AST2600_I2CS_ADDR3_ENABLE BIT(23) ++#define AST2600_I2CS_ADDR3(x) ((x) << 16) ++#define AST2600_I2CS_ADDR2_ENABLE BIT(15) ++#define AST2600_I2CS_ADDR2(x) ((x) << 8) ++#define AST2600_I2CS_ADDR1_ENABLE BIT(7) ++#define AST2600_I2CS_ADDR1(x) (x) + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++/* 0x74 : Target Device Address Register */ ++#define MSIC_CONFIG_ACTIMING1 0x74 ++#define MSIC_I2C_SET_TIMEOUT(s, m) (((s) << 16) | (m)) + -+ if (msg->flags & I2C_M_RECV_LEN) { -+ dev_dbg(i2c_bus->dev, "smbus read\n"); -+ xfer_len = 1; -+ } else if (xfer_len > i2c_bus->buf_size) { -+ xfer_len = i2c_bus->buf_size; -+ } else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) { -+ cmd |= CONTROLLER_TRIGGER_LAST_STOP; -+ } ++/* 0x78 : Misc status */ ++#define MSIC_STATUS 0x78 + -+ writel(AST2600_I2CC_SET_RX_BUF_LEN(xfer_len), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++/* 0x84 : Byte data log */ ++#define BYTE_DATA_LOG 0x84 + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++#define AST2700_I2CC_GET_BUFF(x) ((x) & GENMASK(7, 0)) + -+ return 0; -+} ++/* 0x8c : Target sirq log */ ++#define AST2700_I2CC_SIRQ_LOG 0x8c ++#define SLAVE_ADDR_SHIFT 8 ++#define SLAVE_ADDR_MASK GENMASK(15, 8) ++#define SADDR_NACK BIT(5) ++#define SLAVE_PKT_DONE BIT(4) ++#define SADDR_HIT BIT(3) ++#define SRX_DONE BIT(2) ++#define STX_DONE BIT(1) ++#define SLAVE_STOP BIT(0) + -+static int ast2600_i2c_setup_byte_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++/* 0x94 : I2CC_VERSION_CTRL */ ++#define I2CC_VERSION_CTRL 0x94 ++#define FUNC_CFG_DMA_EN BIT(2) ++/* 0x9c : Misc_2 Debounce Setting */ ++#define MSIC2_CONFIG 0x9C ++#define AST2700_DEBOUNCE_MASK GENMASK(7, 0) ++#define AST2700_DEBOUNCE_LEVEL_MAX 0xFF ++#define AST2700_DEBOUNCE_LEVEL_MIN 0x2 + -+ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_CMD; ++#define I2C_TARGET_MSG_BUF_SIZE 4096 + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++#define AST2600_I2C_DMA_SIZE 4096 + -+ if (msg->flags & I2C_M_RECV_LEN) { -+ dev_dbg(i2c_bus->dev, "smbus read\n"); -+ } else if ((i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) && -+ ((i2c_bus->controller_xfer_cnt + 1) == msg->len)) { -+ cmd |= CONTROLLER_TRIGGER_LAST_STOP; -+ } ++#define CONTROLLER_TRIGGER_LAST_STOP (AST2600_I2CM_RX_CMD_LAST | AST2600_I2CM_STOP_CMD) ++#define TARGET_TRIGGER_CMD (AST2600_I2CS_ACTIVE_ALL | AST2600_I2CS_PKT_MODE_EN) + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++#define AST2600_I2C_TIMEOUT_CLK 0x1 ++#define AST2700_I2C_TIMEOUT_CLK 0x3 + -+ return 0; -+} ++#define AST2600_I2C_TARGET_COUNT 0x3 + -+static int ast2600_i2c_do_start(struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++#define HIGH_MIN_DIV 100000000 ++#define STANDARD_HIGH_MIN_400NS 400 ++#define FAST_HIGH_MIN_60NS 60 ++#define FAST_PLUS_HIGH_MIN_26NS 26 + -+ /* send start */ -+ dev_dbg(i2c_bus->dev, "[%d] %sing %d byte%s %s 0x%02x\n", -+ i2c_bus->msgs_index, msg->flags & I2C_M_RD ? "read" : "write", -+ msg->len, msg->len > 1 ? "s" : "", -+ msg->flags & I2C_M_RD ? "from" : "to", msg->addr); ++#define DATAHOLD_MAX_LEVEL 3 + -+ i2c_bus->controller_xfer_cnt = 0; -+ i2c_bus->buf_index = 0; ++enum xfer_mode { ++ BYTE_MODE, ++ BUFF_MODE, ++ DMA_MODE, ++}; + -+ if (msg->flags & I2C_M_RD) { -+ if (i2c_bus->mode == DMA_MODE) -+ return ast2600_i2c_setup_dma_rx(AST2600_I2CM_START_CMD, i2c_bus); -+ else if (i2c_bus->mode == BUFF_MODE) -+ return ast2600_i2c_setup_buff_rx(AST2600_I2CM_START_CMD, i2c_bus); -+ else -+ return ast2600_i2c_setup_byte_rx(AST2600_I2CM_START_CMD, i2c_bus); -+ } else { -+ if (i2c_bus->mode == DMA_MODE) -+ return ast2600_i2c_setup_dma_tx(AST2600_I2CM_START_CMD, i2c_bus); -+ else if (i2c_bus->mode == BUFF_MODE) -+ return ast2600_i2c_setup_buff_tx(AST2600_I2CM_START_CMD, i2c_bus); -+ else -+ return ast2600_i2c_setup_byte_tx(AST2600_I2CM_START_CMD, i2c_bus); -+ } -+} ++enum i2c_version { ++ AST2600, ++ AST2700, ++}; + -+static int ast2700_i2c_irq_err_to_errno(u32 irq_status) -+{ -+ if (irq_status & AST2700_I2CM_ABNORMAL_ACTION) -+ return -EAGAIN; -+ if (irq_status & (AST2600_I2CM_SDA_DL_TO | AST2600_I2CM_SCL_LOW_TO)) -+ return -EBUSY; -+ if (irq_status & (AST2600_I2CM_ABNORMAL)) -+ return -EPROTO; ++struct i2c_divisor { ++ u32 baseclk_idx; ++ u32 divisor; ++ u8 baseclk_limit; ++}; + -+ return 0; -+} ++struct ast2600_i2c_bus { ++ struct i2c_adapter adap; ++ struct device *dev; ++ void __iomem *reg_base; ++ struct regmap *global_regs; ++ struct clk *clk; ++ struct i2c_timings timing_info; ++ struct completion cmd_complete; ++ struct i2c_msg *msgs; ++ u8 *controller_dma_buf; ++ dma_addr_t controller_dma_addr; ++ u32 apb_clk; ++ struct i2c_divisor clk_divisor; ++ u32 timeout; ++ int irq; ++ int cmd_err; ++ int msgs_index; ++ int msgs_count; ++ int controller_xfer_cnt; ++ size_t buf_index; ++ size_t buf_size; ++ enum xfer_mode mode; ++ enum i2c_version version; ++ bool multi_master; ++ u32 debounce_level; ++ u32 manual_min_high; ++ u32 manual_data_hold; ++ /* Buffer mode */ ++ void __iomem *buf_base; ++ int (*setup_tx)(u32 cmd, struct ast2600_i2c_bus *i2c_bus); ++ int (*setup_rx)(u32 cmd, struct ast2600_i2c_bus *i2c_bus); ++ void (*ac_timing_config)(struct ast2600_i2c_bus *i2c_bus); ++ int (*irq_err_to_errno)(u32 irq_status); ++ void (*irq_clear)(struct ast2600_i2c_bus *i2c_bus, u32 sts); ++ /* smbus alert */ ++ bool alert_enable; ++ struct i2c_smbus_alert_setup alert_data; ++ struct i2c_client *ara; ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ int target_operate; ++ int previous_idx; ++ unsigned char *target_dma_buf; ++ dma_addr_t target_dma_addr; ++ u8 target_attached; ++ struct i2c_client *multi_target[AST2600_I2C_TARGET_COUNT]; ++ struct i2c_client *target; ++ void (*target_packet_irq)(struct ast2600_i2c_bus *i2c_bus, u32 isr); ++ void (*target_byte_irq)(struct ast2600_i2c_bus *i2c_bus, u32 isr); ++#endif ++}; + -+static int ast2600_i2c_irq_err_to_errno(u32 irq_status) ++static u32 i2c_cal_high_min_config(struct ast2600_i2c_bus *i2c_bus, u64 base_clk) +{ -+ if (irq_status & AST2600_I2CM_ARBIT_LOSS) -+ return -EAGAIN; -+ if (irq_status & (AST2600_I2CM_SDA_DL_TO | AST2600_I2CM_SCL_LOW_TO)) -+ return -EBUSY; -+ if (irq_status & (AST2600_I2CM_ABNORMAL)) -+ return -EPROTO; ++ u64 cal, spec_high_min = STANDARD_HIGH_MIN_400NS; + -+ return 0; ++ /* fill the spec high min value */ ++ if (i2c_bus->timing_info.bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ && ++ i2c_bus->timing_info.bus_freq_hz > I2C_MAX_STANDARD_MODE_FREQ) ++ spec_high_min = FAST_HIGH_MIN_60NS; ++ else if (i2c_bus->timing_info.bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ && ++ i2c_bus->timing_info.bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) ++ spec_high_min = FAST_PLUS_HIGH_MIN_26NS; ++ ++ /* round down high minimum value to minimize the impact on the clock high time */ ++ cal = base_clk * spec_high_min; ++ return (u32)DIV_ROUND_DOWN_ULL(cal, HIGH_MIN_DIV); +} + -+static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len; -+ int i; ++ unsigned long base_clk[16]; ++ int baseclk_idx = 0; ++ int divisor = 0; ++ u32 clk_div_reg; ++ u32 scl_low = 0; ++ u32 scl_high = 0; ++ u32 scl_high_min = 0; ++ u32 sda_data_hold = 0; ++ u32 data = 0; + -+ if (i2c_bus->version == AST2700) -+ writel(sts, i2c_bus->reg_base + AST2600_I2CM_ISR); -+ else -+ writel(AST2600_I2CM_PKT_DONE, i2c_bus->reg_base + AST2600_I2CM_ISR); ++ /* Check the maxmum i2c bus frequency */ ++ if (i2c_bus->timing_info.bus_freq_hz > I2C_MAX_ULTRA_FAST_MODE_FREQ) { ++ dev_err(i2c_bus->dev, "The frequency over spec. Set to 100KHz.\n"); ++ i2c_bus->timing_info.bus_freq_hz = AST_DEFAULT_AC_TIMING; ++ } + -+ sts &= ~(AST2600_I2CM_PKT_DONE | AST2600_I2CM_SW_ISR_MASK); ++ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); + -+ switch (sts) { -+ case AST2600_I2CM_PKT_ERROR: -+ i2c_bus->cmd_err = -EAGAIN; -+ complete(&i2c_bus->cmd_complete); -+ break; -+ case AST2600_I2CM_PKT_ERROR | AST2600_I2CM_TX_NAK: /* a0 fix for issue */ -+ fallthrough; -+ case AST2600_I2CM_PKT_ERROR | AST2600_I2CM_TX_NAK | AST2600_I2CM_NORMAL_STOP: -+ i2c_bus->cmd_err = -ENXIO; -+ complete(&i2c_bus->cmd_complete); -+ break; -+ case AST2600_I2CM_NORMAL_STOP: -+ /* write 0 byte only have stop isr */ -+ i2c_bus->msgs_index++; -+ if (i2c_bus->msgs_index < i2c_bus->msgs_count) { -+ if (ast2600_i2c_do_start(i2c_bus)) { -+ i2c_bus->cmd_err = -ENOMEM; -+ complete(&i2c_bus->cmd_complete); -+ } -+ } else { -+ i2c_bus->cmd_err = i2c_bus->msgs_index; -+ complete(&i2c_bus->cmd_complete); -+ } -+ break; -+ case AST2600_I2CM_TX_ACK: -+ case AST2600_I2CM_TX_ACK | AST2600_I2CM_NORMAL_STOP: -+ if (i2c_bus->mode == DMA_MODE) -+ xfer_len = AST2600_I2C_GET_TX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CM_DMA_LEN_STS)); -+ else if (i2c_bus->mode == BUFF_MODE) -+ xfer_len = AST2600_I2CC_GET_TX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); ++ for (int i = 0; i < ARRAY_SIZE(base_clk); i++) { ++ if (i == 0) ++ base_clk[i] = i2c_bus->apb_clk; ++ else if (i < 5) ++ base_clk[i] = (i2c_bus->apb_clk * 2) / ++ (((clk_div_reg >> ((i - 1) * 8)) & GENMASK(7, 0)) + 2); + else -+ xfer_len = 1; -+ -+ i2c_bus->controller_xfer_cnt += xfer_len; -+ -+ if (i2c_bus->controller_xfer_cnt == msg->len) { -+ if (i2c_bus->mode == DMA_MODE) { -+ dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -+ DMA_TO_DEVICE); -+ i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, true); -+ i2c_bus->controller_safe_buf = NULL; -+ } -+ i2c_bus->msgs_index++; -+ if (i2c_bus->msgs_index == i2c_bus->msgs_count) { -+ i2c_bus->cmd_err = i2c_bus->msgs_index; -+ complete(&i2c_bus->cmd_complete); -+ } else { -+ if (ast2600_i2c_do_start(i2c_bus)) { -+ i2c_bus->cmd_err = -ENOMEM; -+ complete(&i2c_bus->cmd_complete); -+ } -+ } -+ } else { -+ if (i2c_bus->mode == DMA_MODE) -+ ast2600_i2c_setup_dma_tx(0, i2c_bus); -+ else if (i2c_bus->mode == BUFF_MODE) -+ ast2600_i2c_setup_buff_tx(0, i2c_bus); -+ else -+ ast2600_i2c_setup_byte_tx(0, i2c_bus); -+ } -+ break; -+ case AST2600_I2CM_RX_DONE: -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ /* -+ * Workaround for controller/target package mode enable rx done stuck issue -+ * When controller go for first read (RX_DONE), target mode will also effect -+ * Then controller will send nack, not operate anymore. -+ */ -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_PKT_MODE_EN) { -+ u32 target_cmd = readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ -+ writel(0, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ writel(target_cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ } -+ fallthrough; -+#endif -+ case AST2600_I2CM_RX_DONE | AST2600_I2CM_NORMAL_STOP: -+ /* do next rx */ -+ if (i2c_bus->mode == DMA_MODE) { -+ xfer_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CM_DMA_LEN_STS)); -+ } else if (i2c_bus->mode == BUFF_MODE) { -+ xfer_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + -+ AST2600_I2CC_BUFF_CTRL)); -+ for (i = 0; i < xfer_len; i++) -+ msg->buf[i2c_bus->controller_xfer_cnt + i] = -+ readb(i2c_bus->buf_base + 0x10 + i); -+ } else { -+ xfer_len = 1; -+ msg->buf[i2c_bus->controller_xfer_cnt] = -+ AST2600_I2CC_GET_RX_BUFF(readl(i2c_bus->reg_base + -+ AST2600_I2CC_STS_AND_BUFF)); ++ base_clk[i] = base_clk[4] >> (i - 4); ++ if ((base_clk[i] / i2c_bus->timing_info.bus_freq_hz) <= 32) { ++ baseclk_idx = i; ++ divisor = DIV_ROUND_UP(base_clk[i], i2c_bus->timing_info.bus_freq_hz); ++ /* calculate the high min value */ ++ scl_high_min = i2c_cal_high_min_config(i2c_bus, (u64)base_clk[i]); ++ dev_dbg(i2c_bus->dev, "scl_high_min: %d\n", scl_high_min); ++ break; + } ++ } + -+ if (msg->flags & I2C_M_RECV_LEN) { -+ u8 recv_len = 0; ++ baseclk_idx = min(baseclk_idx, 15); ++ divisor = min(divisor, 32); ++ scl_low = min(divisor * 9 / 16 - 1, 15); ++ scl_high = (divisor - scl_low - 2) & GENMASK(3, 0); + -+ if (i2c_bus->version == AST2700) { -+ recv_len = AST2700_I2CC_GET_BUFF(readl(i2c_bus->reg_base -+ + BYTE_DATA_LOG)); -+ } else { -+ recv_len = AST2600_I2CC_GET_RX_BUFF(readl(i2c_bus->reg_base -+ + AST2600_I2CC_STS_AND_BUFF)); -+ } ++ if (i2c_bus->manual_min_high) { ++ if (i2c_bus->manual_min_high > scl_high) ++ dev_info(i2c_bus->dev, "invalid manual high min: %d\n", ++ i2c_bus->manual_min_high); ++ else ++ scl_high_min = i2c_bus->manual_min_high; ++ } + -+ msg->len = min_t(unsigned int, recv_len, I2C_SMBUS_BLOCK_MAX); -+ msg->len += ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); -+ msg->flags &= ~I2C_M_RECV_LEN; -+ if (!recv_len) -+ i2c_bus->controller_xfer_cnt = 0; -+ else -+ i2c_bus->controller_xfer_cnt = 1; -+ } else { -+ i2c_bus->controller_xfer_cnt += xfer_len; -+ } ++ if (i2c_bus->manual_data_hold) { ++ if (i2c_bus->manual_data_hold > DATAHOLD_MAX_LEVEL) ++ dev_info(i2c_bus->dev, "invalid manual data hold: %d\n", ++ i2c_bus->manual_data_hold); ++ else ++ sda_data_hold = i2c_bus->manual_data_hold; ++ } + -+ if (i2c_bus->controller_xfer_cnt == msg->len) { -+ if (i2c_bus->mode == DMA_MODE) { -+ dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -+ DMA_FROM_DEVICE); -+ i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, true); -+ i2c_bus->controller_safe_buf = NULL; -+ } ++ data = baseclk_idx; ++ data |= scl_high_min << 20 | scl_high << 16 | scl_low << 12 | sda_data_hold << 10; + -+ i2c_bus->msgs_index++; -+ if (i2c_bus->msgs_index == i2c_bus->msgs_count) { -+ i2c_bus->cmd_err = i2c_bus->msgs_index; -+ complete(&i2c_bus->cmd_complete); -+ } else { -+ if (ast2600_i2c_do_start(i2c_bus)) { -+ i2c_bus->cmd_err = -ENOMEM; -+ complete(&i2c_bus->cmd_complete); -+ } -+ } -+ } else { -+ if (i2c_bus->mode == DMA_MODE) -+ ast2600_i2c_setup_dma_rx(0, i2c_bus); -+ else if (i2c_bus->mode == BUFF_MODE) -+ ast2600_i2c_setup_buff_rx(0, i2c_bus); -+ else -+ ast2600_i2c_setup_byte_rx(0, i2c_bus); -+ } -+ break; -+ default: -+ dev_dbg(i2c_bus->dev, "unhandled sts %x\n", sts); -+ break; ++ if (i2c_bus->timeout) { ++ i2c_bus->timeout = min(i2c_bus->timeout, 31); ++ data |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); ++ data |= AST2600_I2CC_TOUTBASECLK(AST2600_I2C_TIMEOUT_CLK); + } ++ dev_dbg(i2c_bus->dev, "ac: 0x%x\n", data); ++ ++ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); +} + -+static int ast2600_i2c_controller_irq(struct ast2600_i2c_bus *i2c_bus) ++static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) +{ -+ u32 sts = readl(i2c_bus->reg_base + AST2600_I2CM_ISR); -+ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CM_IER); -+ u32 ctrl; -+ -+ /* mask un-used isr bits */ -+ sts &= ~AST2600_I2CM_ISR_MASK; -+ -+ if (!i2c_bus->alert_enable) -+ sts &= ~AST2600_I2CM_SMBUS_ALT; ++ unsigned long base_clk; ++ int baseclk_idx = 0; ++ int divisor = 0; ++ u32 clk_div_reg = 0; ++ u32 scl_low = 0; ++ u32 scl_high = 0; ++ u32 scl_high_min = 0; ++ u32 sda_data_hold = 0; ++ u32 data = 0; ++ u8 divid_term = 0; + -+ if (AST2600_I2CM_BUS_RECOVER_FAIL & sts) { -+ writel(AST2600_I2CM_BUS_RECOVER_FAIL, i2c_bus->reg_base + AST2600_I2CM_ISR); -+ ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ i2c_bus->cmd_err = -EPROTO; -+ complete(&i2c_bus->cmd_complete); -+ return 1; ++ /* Check the maxmum i2c bus frequency */ ++ /* The i2c minmum ac-timing is 12KHz */ ++ if (i2c_bus->timing_info.bus_freq_hz > I2C_MAX_ULTRA_FAST_MODE_FREQ) { ++ dev_err(i2c_bus->dev, "The frequency over spec. Set to 100KHz.\n"); ++ i2c_bus->timing_info.bus_freq_hz = AST_DEFAULT_AC_TIMING; ++ } else if (i2c_bus->timing_info.bus_freq_hz < AST2700_MIN_AC_TIMING) { ++ dev_err(i2c_bus->dev, "The frequency could not be lower than 12KHz.\n"); ++ i2c_bus->timing_info.bus_freq_hz = AST2700_MIN_AC_TIMING; + } + -+ if (AST2600_I2CM_BUS_RECOVER & sts) { -+ writel(AST2600_I2CM_BUS_RECOVER, i2c_bus->reg_base + AST2600_I2CM_ISR); -+ i2c_bus->cmd_err = 0; -+ complete(&i2c_bus->cmd_complete); -+ return 1; -+ } ++ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); + -+ if (AST2600_I2CM_SMBUS_ALT & sts) { -+ if (ier & AST2600_I2CM_SMBUS_ALT) { -+ /* Disable ALT INT */ -+ writel(ier & ~AST2600_I2CM_SMBUS_ALT, i2c_bus->reg_base + AST2600_I2CM_IER); -+ i2c_handle_smbus_alert(i2c_bus->ara); -+ writel(AST2600_I2CM_SMBUS_ALT, i2c_bus->reg_base + AST2600_I2CM_ISR); -+ dev_err(i2c_bus->dev, -+ "ast2600_controller_alert_recv bus id %d, Disable Alt, Please Imple\n", -+ i2c_bus->adap.nr); -+ return 1; ++ /* Find the most used ac-timing */ ++ for (int i = 0; i < 3; i++) { ++ divid_term = ((clk_div_reg >> (i << 3)) & GENMASK(7, 0)); ++ base_clk = (i2c_bus->apb_clk) / (divid_term + 1); ++ if ((base_clk / i2c_bus->timing_info.bus_freq_hz) <= 32) { ++ baseclk_idx = divid_term; ++ divisor = DIV_ROUND_UP(base_clk, i2c_bus->timing_info.bus_freq_hz); ++ break; + } + } + -+ /* handle controller abnormal condition */ -+ if (i2c_bus->version == AST2700) { -+ i2c_bus->cmd_err = ast2700_i2c_irq_err_to_errno(sts); -+ if (i2c_bus->cmd_err) { -+ writel(sts, i2c_bus->reg_base + AST2600_I2CM_ISR); -+ complete(&i2c_bus->cmd_complete); -+ return 1; -+ } -+ } else { -+ i2c_bus->cmd_err = ast2600_i2c_irq_err_to_errno(sts); -+ if (i2c_bus->cmd_err) { -+ writel(AST2600_I2CM_PKT_DONE, i2c_bus->reg_base + AST2600_I2CM_ISR); -+ complete(&i2c_bus->cmd_complete); -+ return 1; ++ /* Can't find a ac-timing then search a fitting one */ ++ if (baseclk_idx == 0) { ++ for (int i = 0; i < 0x100; i++) { ++ base_clk = (i2c_bus->apb_clk) / (i + 1); ++ if ((base_clk / i2c_bus->timing_info.bus_freq_hz) <= 32) { ++ baseclk_idx = i; ++ divisor = DIV_ROUND_UP(base_clk, i2c_bus->timing_info.bus_freq_hz); ++ break; ++ } + } + } + -+ if (AST2600_I2CM_PKT_DONE & sts) { -+ ast2600_i2c_controller_package_irq(i2c_bus, sts); -+ return 1; ++ /* calculate the high min value */ ++ scl_high_min = i2c_cal_high_min_config(i2c_bus, (u64)base_clk); ++ dev_dbg(i2c_bus->dev, "scl_high_min: %d\n", scl_high_min); ++ ++ baseclk_idx = min(baseclk_idx, 0xff); ++ divisor = min(divisor, 32); ++ scl_low = min((DIV_ROUND_UP(divisor * 9, 16)) - 1, 15); ++ scl_high = (divisor - scl_low - 2) & GENMASK(3, 0); ++ ++ /* fill manual min high value */ ++ if (i2c_bus->manual_min_high) { ++ if (i2c_bus->manual_min_high > scl_high) ++ dev_info(i2c_bus->dev, ++ "invalid manual high min: %d\n", i2c_bus->manual_min_high); ++ else ++ scl_high_min = i2c_bus->manual_min_high; + } + -+ return 0; -+} ++ /* fill manual sda hold value */ ++ if (i2c_bus->manual_data_hold) { ++ if (i2c_bus->manual_data_hold > DATAHOLD_MAX_LEVEL) ++ dev_info(i2c_bus->dev, ++ "invalid manual data hold: %d\n", i2c_bus->manual_data_hold); ++ else ++ sda_data_hold = i2c_bus->manual_data_hold; ++ } + -+static irqreturn_t ast2600_i2c_bus_irq(int irq, void *dev_id) -+{ -+ struct ast2600_i2c_bus *i2c_bus = dev_id; ++ data = baseclk_idx; ++ data |= scl_high_min << 20 | scl_high << 16 | scl_low << 12 | sda_data_hold << 10; + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ if (readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL) & AST2600_I2CC_SLAVE_EN) { -+ if (ast2600_i2c_target_irq(i2c_bus)) -+ return IRQ_HANDLED; ++ if (i2c_bus->timeout) { ++ i2c_bus->timeout = min(i2c_bus->timeout, 255); ++ writel(MSIC_I2C_SET_TIMEOUT(i2c_bus->timeout, 0), ++ i2c_bus->reg_base + MSIC_CONFIG_ACTIMING1); ++ /* timeout_base set as 1ms */ ++ data |= AST2600_I2CC_TOUTBASECLK(AST2700_I2C_TIMEOUT_CLK); + } -+#endif -+ return IRQ_RETVAL(ast2600_i2c_controller_irq(i2c_bus)); ++ dev_dbg(i2c_bus->dev, "ac: 0x%x\n", data); ++ ++ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); +} + -+static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(adap); -+ unsigned long timeout; -+ int ret; ++ u32 state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ u32 ctrl; ++ int ret = 0; ++ int r; + -+ if (!i2c_bus->multi_master && -+ (readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) & AST2600_I2CC_BUS_BUSY_STS)) { -+ ret = ast2600_i2c_recover_bus(i2c_bus); -+ if (ret) -+ return ret; -+ } ++ dev_dbg(i2c_bus->dev, "%d-bus recovery bus [%x]\n", i2c_bus->adap.nr, state); + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ if (i2c_bus->mode == BUFF_MODE) { -+ if (i2c_bus->target_operate) -+ return -EBUSY; -+ /* disable target isr */ -+ writel(0, i2c_bus->reg_base + AST2600_I2CS_IER); -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR) || i2c_bus->target_operate) { -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); -+ return -EBUSY; -+ } -+ } -+#endif ++ /* reset i2c controller to avoid the bus getting stuck */ ++ ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(ctrl & ~AST2600_I2CC_MASTER_EN, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); + -+ i2c_bus->cmd_err = 0; -+ i2c_bus->msgs = msgs; -+ i2c_bus->msgs_index = 0; -+ i2c_bus->msgs_count = num; + reinit_completion(&i2c_bus->cmd_complete); -+ ret = ast2600_i2c_do_start(i2c_bus); -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ /* avoid race condication target is wait and controller wait 1st target operate */ -+ if (i2c_bus->mode == BUFF_MODE) -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); -+#endif -+ if (ret) -+ goto controller_out; -+ timeout = wait_for_completion_timeout(&i2c_bus->cmd_complete, i2c_bus->adap.timeout); -+ if (timeout == 0) { -+ u32 ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ i2c_bus->cmd_err = 0; + -+ dev_dbg(i2c_bus->dev, "timeout isr[%x], sts[%x]\n", -+ readl(i2c_bus->reg_base + AST2600_I2CM_ISR), -+ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); -+ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ if (i2c_bus->multi_master && -+ (readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) & -+ AST2600_I2CC_BUS_BUSY_STS)) -+ ast2600_i2c_recover_bus(i2c_bus); -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ if (ctrl & AST2600_I2CC_SLAVE_EN) { -+ u32 cmd = TARGET_TRIGGER_CMD; -+ -+ if (i2c_bus->mode == DMA_MODE) { -+ cmd |= AST2600_I2CS_RX_DMA_EN; -+ writel(lower_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_RX_DMA); -+ writel(upper_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); -+ writel(lower_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_TX_DMA); -+ writel(upper_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -+ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ } else if (i2c_bus->mode == BUFF_MODE) { -+ cmd = TARGET_TRIGGER_CMD; -+ } else { -+ cmd &= ~AST2600_I2CS_PKT_MODE_EN; -+ } -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ /* Check SDA/SCL status in the status register. */ ++ state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ if (!(state & AST2600_I2CC_SDA_LINE_STS) && (state & AST2600_I2CC_SCL_LINE_STS)) { ++ writel(AST2600_I2CM_RECOVER_CMD_EN, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ r = wait_for_completion_timeout(&i2c_bus->cmd_complete, i2c_bus->adap.timeout); ++ if (r == 0) { ++ dev_dbg(i2c_bus->dev, "recovery timed out\n"); ++ return -ETIMEDOUT; ++ } else if (i2c_bus->cmd_err) { ++ dev_dbg(i2c_bus->dev, "recovery error\n"); ++ ret = -EPROTO; + } -+#endif -+ ret = -ETIMEDOUT; -+ } else { -+ ret = i2c_bus->cmd_err; + } + -+ dev_dbg(i2c_bus->dev, "bus%d-m: %d end\n", i2c_bus->adap.nr, i2c_bus->cmd_err); ++ /* Recovery done */ ++ state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ if (state & AST2600_I2CC_BUS_BUSY_STS) { ++ dev_dbg(i2c_bus->dev, "Can't recover bus [%x]\n", state); ++ ret = -EPROTO; ++ } + -+controller_out: -+ if (i2c_bus->mode == DMA_MODE) { -+ /* still have controller_safe_buf need to be released */ -+ if (i2c_bus->controller_safe_buf) { -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ return ret; ++} + -+ if (msg->flags & I2C_M_RD) -+ dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -+ DMA_FROM_DEVICE); -+ else -+ dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -+ DMA_TO_DEVICE); -+ i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, true); -+ i2c_bus->controller_safe_buf = NULL; ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++static void ast2700_i2c_get_target(struct ast2600_i2c_bus *i2c_bus, u8 addr) ++{ ++ u8 i = 0; ++ bool target_find = false; ++ ++ /* find target by address */ ++ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { ++ if (i2c_bus->multi_target[i]) { ++ if (i2c_bus->multi_target[i]->addr == addr) { ++ dev_dbg(i2c_bus->dev, "address [%x] on %d\n", addr, i); ++ i2c_bus->target = i2c_bus->multi_target[i]; ++ target_find = true; ++ } + } + } + -+ return ret; ++ if (!target_find) ++ dev_err(i2c_bus->dev, "address [%x] could not find\n", addr); +} + -+static void ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) ++static void ast2700_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 isr) +{ -+ struct platform_device *pdev = to_platform_device(i2c_bus->dev); -+ u32 fun_ctrl = AST2600_I2CC_BUS_AUTO_RELEASE | AST2600_I2CC_MASTER_EN; -+ -+ /* I2C Reset */ -+ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; ++ u32 sirq_log; ++ u32 sts; + -+ i2c_bus->multi_master = device_property_read_bool(&pdev->dev, "multi-master"); -+ if (!i2c_bus->multi_master) -+ fun_ctrl |= AST2600_I2CC_MULTI_MASTER_DIS; ++ writel(AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_WAIT_RX_DMA, ++ i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + -+ /* I2C Debounce level */ -+ if (i2c_bus->version != AST2600) { -+ if (!device_property_read_u32(&pdev->dev, "debounce-level", -+ &i2c_bus->debounce_level)) { -+ u32 debounce_level = 0; ++ sts = isr & ~(AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_ADDR_NAK_MASK); ++ /* Handle i2c target timeout condition */ ++ if (sts & AST2600_I2CS_INACTIVE_TO) { ++ dev_dbg(i2c_bus->dev, "The target timeout occurs isr: 0x%08x.\n", isr); ++ /* Reset timeout counter */ ++ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & ++ AST2600_I2CC_AC_TIMING_MASK; + -+ /* AST2700 support manual debounce setting */ -+ if (i2c_bus->version == AST2700) { -+ if (i2c_bus->debounce_level > AST2700_DEBOUNCE_LEVEL_MAX) -+ i2c_bus->debounce_level = AST2700_DEBOUNCE_LEVEL_MAX; -+ if (i2c_bus->debounce_level < AST2700_DEBOUNCE_LEVEL_MIN) -+ i2c_bus->debounce_level = AST2700_DEBOUNCE_LEVEL_MIN; ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ ac_timing |= AST2700_I2CC_TTIMEOUT(i2c_bus->timeout); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ /* clear sirq log */ ++ while ((sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG))) { ++ /* assign the target client*/ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, ++ sirq_log >> SLAVE_ADDR_SHIFT); + } ++ }; ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ } ++ return; ++ } + -+ debounce_level = readl(i2c_bus->reg_base + MSIC2_CONFIG) -+ & ~(AST2700_DEBOUNCE_MASK); ++ if (sts & AST2600_I2CS_ABNOR_STOP) { ++ dev_err(i2c_bus->dev, "The target abnomal protocol occurs isr: 0x%08x.\n", isr); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ /* clear sirq log */ ++ while ((sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG))) { ++ /* assign the target client*/ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, ++ sirq_log >> SLAVE_ADDR_SHIFT); ++ } ++ }; ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ } ++ return; ++ } + -+ debounce_level |= i2c_bus->debounce_level; -+ writel(debounce_level, i2c_bus->reg_base + MSIC2_CONFIG); ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR); + -+ fun_ctrl |= AST2700_I2CC_MANUAL_DEBOUNCE; ++ switch (sts) { ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_RX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* bug workaround */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_SLAVE_MATCH | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* workaround: false alarm target match check */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* workaround new target match */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ /* workaround: not clear target match due to wait next isr check tx or rx */ ++ isr &= ~AST2600_I2CS_SLAVE_MATCH; ++ break; ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_TX_NAK | ++ AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_TX_ACK | AST2600_I2CS_WAIT_TX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } + } -+ } -+ -+ /* Enable Controller Mode */ -+ writel(fun_ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ /* Disable Target Address */ -+ writel(0, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); -+ -+ /* Set AC Timing */ -+ if (i2c_bus->version == AST2700) -+ ast2700_i2c_ac_timing_config(i2c_bus); -+ else -+ ast2600_i2c_ac_timing_config(i2c_bus); -+ -+ /* Clear Interrupt */ -+ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ default: ++ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts, ++ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ /* for memory buffer initial */ -+ if (i2c_bus->mode == DMA_MODE) { -+ i2c_bus->target_dma_buf = -+ dmam_alloc_coherent(i2c_bus->dev, I2C_TARGET_MSG_BUF_SIZE, -+ &i2c_bus->target_dma_addr, GFP_KERNEL); -+ if (!i2c_bus->target_dma_buf) -+ return; ++ /* clear sirq log */ ++ while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) ++ ; ++ break; + } + -+ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CS_ISR); ++ if (cmd) ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+ if (i2c_bus->mode == BYTE_MODE) -+ writel(GENMASK(15, 0), i2c_bus->reg_base + AST2600_I2CS_IER); -+ else -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); -+#endif ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); +} + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+static int ast2600_i2c_reg_target(struct i2c_client *client) ++static void ast2700_i2c_target_packet_buff_irq(struct ast2600_i2c_bus *i2c_bus, u32 isr) +{ -+ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter); -+ u32 cmd = TARGET_TRIGGER_CMD; -+ u32 target_addr = readl(i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); -+ u32 ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ bool target_reg = false; -+ u8 i = 0; ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; ++ u32 sirq_log; ++ u32 sts; + -+ /* check target client input and target counts*/ -+ if (!client || i2c_bus->target_attached == AST2600_I2C_TARGET_COUNT) -+ return -EINVAL; ++ writel(AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_WAIT_RX_DMA, ++ i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + -+ /* check duplicate address */ -+ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { -+ if (i2c_bus->multi_target[i]) { -+ if (i2c_bus->multi_target[i]->addr == client->addr) { -+ dev_dbg(i2c_bus->dev, "duplicate address [%x] on %d\n", client->addr, i); -+ return -EINVAL; ++ sts = isr & ~(AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_ADDR_NAK_MASK); ++ /* Handle i2c target timeout condition */ ++ if (sts & AST2600_I2CS_INACTIVE_TO) { ++ dev_dbg(i2c_bus->dev, "The target timeout occurs isr: 0x%08x.\n", isr); ++ /* Reset timeout counter */ ++ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & ++ AST2600_I2CC_AC_TIMING_MASK; ++ ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ ac_timing |= AST2700_I2CC_TTIMEOUT(i2c_bus->timeout); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ writel(TARGET_TRIGGER_CMD, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ /* clear sirq log */ ++ while ((sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG))) { ++ /* assign the target client*/ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, ++ sirq_log >> SLAVE_ADDR_SHIFT); + } ++ }; ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; + } ++ i2c_bus->target_operate = 0; ++ return; + } + -+ /* assign the target address into array */ -+ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { -+ if (!i2c_bus->multi_target[i]) { -+ i2c_bus->multi_target[i] = client; -+ target_reg = true; -+ dev_dbg(i2c_bus->dev, "reg [%x] on %d\n", client->addr, i); -+ -+ /* set target addr by index */ -+ switch (i) { -+ case 0: -+ target_addr &= ~(AST2600_I2CS_ADDR1_MASK); -+ target_addr |= (AST2600_I2CS_ADDR1(client->addr) -+ | AST2600_I2CS_ADDR1_ENABLE); -+ break; -+ case 1: -+ target_addr &= ~(AST2600_I2CS_ADDR2_MASK); -+ target_addr |= (AST2600_I2CS_ADDR2(client->addr) -+ | AST2600_I2CS_ADDR2_ENABLE); -+ break; -+ case 2: -+ target_addr &= ~(AST2600_I2CS_ADDR3_MASK); -+ target_addr |= (AST2600_I2CS_ADDR3(client->addr) -+ | AST2600_I2CS_ADDR3_ENABLE); -+ break; ++ if (sts & AST2600_I2CS_ABNOR_STOP) { ++ dev_err(i2c_bus->dev, "The target abnomal protocol occurs isr: 0x%08x.\n", isr); ++ writel(TARGET_TRIGGER_CMD, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ /* clear sirq log */ ++ while ((sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG))) { ++ /* assign the target client*/ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, ++ sirq_log >> SLAVE_ADDR_SHIFT); + } -+ -+ /* Set target addr. */ -+ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); -+ break; ++ }; ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; + } ++ i2c_bus->target_operate = 0; ++ return; + } + -+ /* don't reg target */ -+ if (!target_reg) -+ return -EINVAL; -+ -+ dev_dbg(i2c_bus->dev, "target addr %x\n", client->addr); -+ -+ /* turn on target mode */ -+ if (!(ctrl & AST2600_I2CC_SLAVE_EN)) { -+ writel(ctrl | AST2600_I2CC_SLAVE_EN, -+ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ } ++ if (sts & AST2600_I2CS_SLAVE_MATCH) ++ i2c_bus->target_operate = 1; + -+ /* trigger rx buffer */ -+ if (i2c_bus->mode == DMA_MODE) { -+ cmd |= AST2600_I2CS_RX_DMA_EN; -+ writel(lower_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_RX_DMA); -+ writel(upper_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); -+ writel(lower_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_TX_DMA); -+ writel(upper_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); -+ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR); ++ dev_dbg(i2c_bus->dev, "sts %x\n", sts); ++ switch (sts) { ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_RX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), + i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -+ } else if (i2c_bus->mode == BUFF_MODE) { -+ cmd = TARGET_TRIGGER_CMD; -+ } else { -+ cmd &= ~AST2600_I2CS_PKT_MODE_EN; -+ } -+ -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ -+ i2c_bus->target_attached++; -+ return 0; -+} -+ -+static int ast2600_i2c_unreg_target(struct i2c_client *client) -+{ -+ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter); -+ u32 target_addr = readl(i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); -+ bool target_unreg = false; -+ u8 i = 0; -+ -+ /* check target client input and salve counts*/ -+ if (!client || i2c_bus->target_attached == 0) -+ return -EINVAL; -+ -+ /* remove the target call back from array */ -+ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { -+ if (i2c_bus->multi_target[i]) { -+ if (i2c_bus->multi_target[i]->addr == client->addr) { -+ i2c_bus->multi_target[i] = NULL; -+ target_unreg = true; -+ dev_dbg(i2c_bus->dev, "un-reg [%x] from %d\n", client->addr, i); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* bug workaround */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_SLAVE_MATCH | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* workaround: false alarm target match check */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* workaround new target match */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ /* workaround: not clear target match due to wait next isr check tx or rx */ ++ isr &= ~AST2600_I2CS_SLAVE_MATCH; ++ break; ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_TX_NAK | ++ AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); + -+ /* remove target addr by index */ -+ switch (i) { -+ case 0: -+ target_addr &= ~(AST2600_I2CS_ADDR1_MASK | AST2600_I2CS_ADDR1_ENABLE); -+ break; -+ case 1: -+ target_addr &= ~(AST2600_I2CS_ADDR2_MASK | AST2600_I2CS_ADDR2_ENABLE); -+ break; -+ case 2: -+ target_addr &= ~(AST2600_I2CS_ADDR3_MASK | AST2600_I2CS_ADDR3_ENABLE); -+ break; ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_TX_ACK | AST2600_I2CS_WAIT_TX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_SADDR_PENDING | AST2600_I2CS_WAIT_TX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ writel(AST2600_I2CS_SLAVE_MATCH, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ } ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base + 0x20); ++ } ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_RX_DONE: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ /* workaround: false alarm target match check */ ++ if (sirq_log & SADDR_HIT) { ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); + } -+ -+ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); -+ break; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ } ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); + } + } -+ } -+ -+ /* don't un-reg target */ -+ if (!target_unreg) -+ return -EINVAL; -+ -+ i2c_bus->target_attached--; ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_STOP: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (i2c_bus->target) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target = NULL; ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA: ++ sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG); ++ if (!i2c_bus->target) ++ ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ if (i2c_bus->target) { ++ value = readb(i2c_bus->buf_base + 0x30 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ default: ++ dev_err(i2c_bus->dev, "unhandled target isr case %x, isr %x, sts %x\n", sts, ++ isr, ++ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); + -+ /* Turn off target mode */ -+ if (i2c_bus->target_attached == 0x0) { -+ writel(~AST2600_I2CC_SLAVE_EN & readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL), -+ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ /* clear sirq log */ ++ while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) ++ ; ++ break; + } + -+ return 0; -+} -+#endif ++ if (cmd) ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+static u32 ast2600_i2c_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; -+} ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + -+static const struct i2c_algorithm i2c_ast2600_algorithm = { -+ .xfer = ast2600_i2c_controller_xfer, -+ .functionality = ast2600_i2c_functionality, -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ .reg_target = ast2600_i2c_reg_target, -+ .unreg_target = ast2600_i2c_unreg_target, -+#endif -+}; ++ if ((sts & AST2600_I2CS_STOP) && !(sts & AST2600_I2CS_SLAVE_PENDING)) ++ i2c_bus->target_operate = 0; ++ else ++ i2c_bus->previous_idx = AST2600_I2CS_GET_TARGET(sts); ++} + -+static int ast2600_i2c_probe(struct platform_device *pdev) ++static void ast2600_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ struct device *dev = &pdev->dev; -+ struct ast2600_i2c_bus *i2c_bus; -+ const char *xfer_mode; -+ struct resource *res; -+ u32 global_ctrl; -+ int ret; -+ -+ i2c_bus = devm_kzalloc(dev, sizeof(*i2c_bus), GFP_KERNEL); -+ if (!i2c_bus) -+ return -ENOMEM; -+ -+ i2c_bus->version = (enum i2c_version)device_get_match_data(dev); -+ -+ i2c_bus->reg_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(i2c_bus->reg_base)) -+ return PTR_ERR(i2c_bus->reg_base); ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; + -+ i2c_bus->rst = devm_reset_control_get_shared(dev, NULL); -+ if (IS_ERR(i2c_bus->rst)) -+ return dev_err_probe(dev, PTR_ERR(i2c_bus->rst), "Missing reset ctrl\n"); ++ sts &= ~(AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_SADDR_PENDING ++ | AST2600_I2CS_ADDR_NAK_MASK); + -+ reset_control_deassert(i2c_bus->rst); ++ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; + -+ i2c_bus->global_regs = -+ syscon_regmap_lookup_by_phandle(dev_of_node(dev), "aspeed,global-regs"); -+ if (IS_ERR(i2c_bus->global_regs)) -+ return PTR_ERR(i2c_bus->global_regs); ++ /* Handle i2c target timeout condition */ ++ if (sts & AST2600_I2CS_INACTIVE_TO) { ++ /* Reset time out counter */ ++ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & ++ AST2600_I2CC_AC_TIMING_MASK; + -+ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CTRL, &global_ctrl); -+ if ((global_ctrl & AST2600_GLOBAL_INIT) != AST2600_GLOBAL_INIT) { -+ regmap_write(i2c_bus->global_regs, AST2600_I2CG_CTRL, AST2600_GLOBAL_INIT); -+ if (i2c_bus->version == AST2600) -+ regmap_write(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, AST2600_I2CCG_DIV_CTRL); -+ else -+ regmap_write(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, AST2700_I2CCG_DIV_CTRL); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ /* set rx dma length ,re-send target trigger command and clear irq status */ ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ writel(TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN, ++ i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ return; + } + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ i2c_bus->target_operate = 0; -+ i2c_bus->target_attached = 0; -+ for (int i = 0; i < AST2600_I2C_TARGET_COUNT; i++) -+ i2c_bus->multi_target[i] = NULL; -+#endif -+ i2c_bus->dev = dev; -+ if (i2c_bus->version == AST2600) { -+ i2c_bus->mode = BUFF_MODE; ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); + -+ if (!device_property_read_string(dev, "aspeed,transfer-mode", &xfer_mode)) { -+ if (!strcmp(xfer_mode, "dma")) -+ i2c_bus->mode = DMA_MODE; -+ else if (!strcmp(xfer_mode, "byte")) -+ i2c_bus->mode = BYTE_MODE; -+ else -+ i2c_bus->mode = BUFF_MODE; ++ switch (sts) { ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); + } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE_NAK | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_RX_DMA | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_RX_DONE_NAK | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_STOP: ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ if (sts & AST2600_I2CS_SLAVE_MATCH) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); + -+ if (i2c_bus->mode == BUFF_MODE) { -+ i2c_bus->buf_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); -+ if (IS_ERR(i2c_bus->buf_base)) -+ i2c_bus->mode = BYTE_MODE; -+ else -+ i2c_bus->buf_size = resource_size(res) / 2; ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); + } -+ } else { -+ i2c_bus->mode = DMA_MODE; -+ } ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ if (sts & AST2600_I2CS_STOP) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; + -+ /* -+ * i2c timeout counter: use base clk4 1Mhz, -+ * per unit: 1/(1000/1024) = 1024us -+ * lower than 1024 us will be set 1 ms. -+ */ -+ ret = device_property_read_u32(dev, "i2c-scl-clk-low-timeout-us", &i2c_bus->timeout); -+ if (!ret) { -+ i2c_bus->timeout /= 1024; ++ /* it is Mw data Mr coming -> it need send tx */ ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA: ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA: ++ /* it should be repeat start read */ ++ if (sts & AST2600_I2CS_SLAVE_MATCH) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); + -+ if (!i2c_bus->timeout) -+ i2c_bus->timeout = 1; ++ target_rx_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CS_DMA_LEN_STS)); ++ for (i = 0; i < target_rx_len; i++) { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, ++ &i2c_bus->target_dma_buf[i]); ++ } ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA: ++ /* First Start read */ ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, ++ &i2c_bus->target_dma_buf[0]); ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA: ++ /* it should be next start read */ ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, ++ &i2c_bus->target_dma_buf[0]); ++ writel(AST2600_I2CS_SET_TX_DMA_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_DMA_EN; ++ break; ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | AST2600_I2CS_SLAVE_MATCH: ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: ++ /* it just tx complete */ ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_DMA_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ break; ++ case AST2600_I2CS_STOP: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ break; ++ default: ++ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts, ++ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); ++ break; + } + -+ init_completion(&i2c_bus->cmd_complete); -+ -+ i2c_bus->irq = platform_get_irq(pdev, 0); -+ if (i2c_bus->irq < 0) -+ return i2c_bus->irq; -+ -+ platform_set_drvdata(pdev, i2c_bus); -+ -+ i2c_bus->clk = devm_clk_get(i2c_bus->dev, NULL); -+ if (IS_ERR(i2c_bus->clk)) -+ return dev_err_probe(i2c_bus->dev, PTR_ERR(i2c_bus->clk), "Can't get clock\n"); -+ -+ i2c_bus->apb_clk = clk_get_rate(i2c_bus->clk); -+ -+ i2c_parse_fw_timings(i2c_bus->dev, &i2c_bus->timing_info, true); -+ -+ /* Initialize the I2C adapter */ -+ i2c_bus->adap.owner = THIS_MODULE; -+ i2c_bus->adap.algo = &i2c_ast2600_algorithm; -+ i2c_bus->adap.retries = 0; -+ i2c_bus->adap.dev.parent = i2c_bus->dev; -+ device_set_node(&i2c_bus->adap.dev, dev_fwnode(dev)); -+ i2c_bus->adap.algo_data = i2c_bus; -+ strscpy(i2c_bus->adap.name, pdev->name, sizeof(i2c_bus->adap.name)); -+ i2c_set_adapdata(&i2c_bus->adap, i2c_bus); -+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -+ -+ ast2600_i2c_init(i2c_bus); -+ -+ ret = devm_request_irq(dev, i2c_bus->irq, ast2600_i2c_bus_irq, 0, -+ dev_name(dev), i2c_bus); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "Unable to request irq %d\n", i2c_bus->irq); ++ if (cmd) ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+ /* Set interrupt generation of i2c controller */ -+ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER, -+ i2c_bus->reg_base + AST2600_I2CM_IER); ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++} + -+ ret = devm_i2c_add_adapter(dev, &i2c_bus->adap); -+ if (ret) -+ return ret; ++static void ast2600_i2c_target_packet_buff_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++{ ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; + -+ i2c_bus->alert_enable = device_property_read_bool(dev, "smbus-alert"); -+ if (i2c_bus->alert_enable) { -+ i2c_bus->ara = i2c_new_smbus_alert_device(&i2c_bus->adap, &i2c_bus->alert_data); -+ if (!i2c_bus->ara) -+ dev_warn(dev, "Failed to register ARA client\n"); -+ else -+ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER | -+ AST2600_I2CM_SMBUS_ALT, -+ i2c_bus->reg_base + AST2600_I2CM_IER); -+ } else { -+ i2c_bus->alert_enable = false; ++ /* due to controller target is common buffer, need force the master stop not issue */ ++ if (readl(i2c_bus->reg_base + AST2600_I2CM_CMD_STS) & GENMASK(15, 0)) { ++ writel(0, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ i2c_bus->cmd_err = -EBUSY; ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ complete(&i2c_bus->cmd_complete); + } + -+ dev_info(dev, "%s [%d]: adapter [%d KHz] mode [%d] version [%d]\n", -+ dev->of_node->name, i2c_bus->adap.nr, i2c_bus->timing_info.bus_freq_hz / 1000, -+ i2c_bus->mode, i2c_bus->version); ++ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; + -+ return 0; -+} ++ /* Handle i2c target timeout condition */ ++ if (sts & AST2600_I2CS_INACTIVE_TO) { ++ /* Reset timeout counter */ ++ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & ++ AST2600_I2CC_AC_TIMING_MASK; + -+static void ast2600_i2c_remove(struct platform_device *pdev) -+{ -+ struct ast2600_i2c_bus *i2c_bus = platform_get_drvdata(pdev); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ /* Re-send target trigger command and clear irq */ ++ writel(TARGET_TRIGGER_CMD, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target_operate = 0; ++ return; ++ } + -+ /* Disable everything. */ -+ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(0, i2c_bus->reg_base + AST2600_I2CM_IER); -+} ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); + -+static const struct of_device_id ast2600_i2c_bus_of_table[] = { -+ { .compatible = "aspeed,ast2600-i2cv2", .data = (const void *)AST2600, }, -+ { .compatible = "aspeed,ast2700-i2c", .data = (const void *)AST2700, }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, ast2600_i2c_bus_of_table); ++ if (sts & AST2600_I2CS_SLAVE_MATCH) ++ i2c_bus->target_operate = 1; + -+static struct platform_driver ast2600_i2c_bus_driver = { -+ .probe = ast2600_i2c_probe, -+ .remove_new = ast2600_i2c_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = ast2600_i2c_bus_of_table, -+ }, -+}; ++ switch (sts) { ++ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_SLAVE_PENDING | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ case AST2600_I2CS_SLAVE_PENDING | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ fallthrough; ++ case AST2600_I2CS_SLAVE_PENDING | ++ AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ cmd = TARGET_TRIGGER_CMD; ++ if (sts & AST2600_I2CS_RX_DONE) { ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ } ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_RX_BUFF_EN) ++ cmd = 0; ++ else ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN; + -+module_platform_driver(ast2600_i2c_bus_driver); ++ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ break; ++ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_RX_DONE: ++ cmd = TARGET_TRIGGER_CMD; ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ cmd |= AST2600_I2CS_RX_BUFF_EN; ++ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ break; ++ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA | ++ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ cmd = TARGET_TRIGGER_CMD; ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ cmd |= AST2600_I2CS_RX_BUFF_EN; ++ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ break; ++ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ cmd = TARGET_TRIGGER_CMD; ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ /* workaround for avoid next start with len != 0 */ ++ writel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ break; ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP: ++ cmd = TARGET_TRIGGER_CMD; ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ /* workaround for avoid next start with len != 0 */ ++ writel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ break; ++ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE | ++ AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_STOP: ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base); ++ break; ++ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ writeb(value, i2c_bus->buf_base); ++ writel(AST2600_I2CC_SET_TX_BUF_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN; ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE: ++ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE: ++ case AST2600_I2CS_WAIT_TX_DMA: ++ /* it should be repeat start read */ ++ if (sts & AST2600_I2CS_SLAVE_MATCH) ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); + -+MODULE_AUTHOR("Ryan Chen "); -+MODULE_DESCRIPTION("ASPEED AST2600 I2C Controller Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/i3c/master/ast2600-i3c-master.c b/drivers/i3c/master/ast2600-i3c-master.c ---- a/drivers/i3c/master/ast2600-i3c-master.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/i3c/master/ast2600-i3c-master.c 2025-12-23 10:16:21.088033273 +0000 -@@ -10,6 +10,8 @@ - #include - #include - #include -+#include -+#include - - #include "dw-i3c-master.h" - -@@ -33,18 +35,93 @@ - #define AST2600_I3CG_REG1_SA_EN BIT(15) - #define AST2600_I3CG_REG1_INST_ID_MASK GENMASK(19, 16) - #define AST2600_I3CG_REG1_INST_ID(x) (((x) << 16) & AST2600_I3CG_REG1_INST_ID_MASK) -+#define SCL_SW_MODE_OE BIT(20) -+#define SCL_OUT_SW_MODE_VAL BIT(21) -+#define SCL_IN_SW_MODE_VAL BIT(23) -+#define SDA_SW_MODE_OE BIT(24) -+#define SDA_OUT_SW_MODE_VAL BIT(25) -+#define SDA_IN_SW_MODE_VAL BIT(27) -+#define SCL_IN_SW_MODE_EN BIT(28) -+#define SDA_IN_SW_MODE_EN BIT(29) -+#define SCL_OUT_SW_MODE_EN BIT(30) -+#define SDA_OUT_SW_MODE_EN BIT(31) - - #define AST2600_DEFAULT_SDA_PULLUP_OHMS 2000 - -+#define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) -+#define DEV_ADDR_TABLE_DYNAMIC_ADDR GENMASK(23, 16) -+#define DEV_ADDR_TABLE_IBI_ADDR_MASK GENMASK(25, 24) -+#define IBI_ADDR_MASK_OFF 0b00 -+#define IBI_ADDR_MASK_LAST_3BITS 0b01 -+#define IBI_ADDR_MASK_LAST_4BITS 0b10 -+#define DEV_ADDR_TABLE_DA_PARITY BIT(23) -+#define DEV_ADDR_TABLE_MR_REJECT BIT(14) -+#define DEV_ADDR_TABLE_SIR_REJECT BIT(13) -+#define DEV_ADDR_TABLE_IBI_MDB BIT(12) - #define DEV_ADDR_TABLE_IBI_PEC BIT(11) -+#define DEV_ADDR_TABLE_STATIC_ADDR GENMASK(6, 0) ++ if (sts & AST2600_I2CS_RX_DONE) { ++ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ for (i = 0; i < target_rx_len; i++) { ++ value = readb(i2c_bus->buf_base + 0x10 + i); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value); ++ } ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value); ++ } else { ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &value); ++ } ++ writeb(value, i2c_bus->buf_base); ++ writel(AST2600_I2CC_SET_TX_BUF_LEN(1), ++ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN; ++ break; ++ /* workaround : trigger the cmd twice to fix next state keep 1000000 */ ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN; ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ break; ++ /* the pending slave needs to be cleared with TX_NAK and STOP here */ ++ /* other flags will be handled in the next irq callback */ ++ /* the slave index will be updated when the slave match occurs */ ++ /* use the pervious idx to do the slave stop event */ ++ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE: ++ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP | ++ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: ++ cmd = TARGET_TRIGGER_CMD; ++ i2c_bus->target = i2c_bus->multi_target[i2c_bus->previous_idx]; ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target_operate = 0; ++ break; ++ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP: ++ case AST2600_I2CS_STOP: ++ cmd = TARGET_TRIGGER_CMD; ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ break; ++ default: ++ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts, ++ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); ++ break; ++ } + -+#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) ++ if (cmd) ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + -+#define DEVICE_CTRL 0x0 -+#define DEV_CTRL_SLAVE_MDB GENMASK(23, 16) -+#define DEV_CTRL_HOT_JOIN_NACK BIT(8) ++ if ((sts & AST2600_I2CS_STOP) && !(sts & AST2600_I2CS_SLAVE_PENDING)) ++ i2c_bus->target_operate = 0; ++ else ++ i2c_bus->previous_idx = AST2600_I2CS_GET_TARGET(sts); ++} + -+#define NUM_OF_SWDATS_IN_GROUP 8 -+#define ALL_DATS_IN_GROUP_ARE_FREE ((1 << NUM_OF_SWDATS_IN_GROUP) - 1) -+#define NUM_OF_SWDAT_GROUP 16 ++static void ast2600_i2c_target_byte_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++{ ++ u32 i2c_buff = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ u32 cmd = AST2600_I2CS_ACTIVE_ALL; ++ u8 byte_data; ++ u8 value; + -+#define ADDR_GRP_MASK GENMASK(6, 3) -+#define ADDR_GRP(x) (((x) & ADDR_GRP_MASK) >> 3) -+#define ADDR_HID_MASK GENMASK(2, 0) -+#define ADDR_HID(x) ((x) & ADDR_HID_MASK) ++ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; + -+#define IBI_QUEUE_STATUS 0x18 ++ /* Handle i2c target timeout condition */ ++ if (sts & AST2600_I2CS_INACTIVE_TO) { ++ /* Reset time out counter */ ++ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) & ++ AST2600_I2CC_AC_TIMING_MASK; + -+#define IBI_SIR_REQ_REJECT 0x30 -+#define INTR_STATUS_EN 0x40 -+#define INTR_SIGNAL_EN 0x44 -+#define INTR_IBI_THLD_STAT BIT(2) ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); ++ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ /* Re-send target trigger command and clear irq */ ++ writel(AST2600_I2CS_ACTIVE_ALL, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ writel(sts, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ i2c_bus->target_operate = 0; ++ return; ++ } + -+#define PRESENT_STATE 0x54 -+#define CM_TFR_STS GENMASK(13, 8) -+#define CM_TFR_STS_MASTER_SERV_IBI 0xe -+#define SDA_LINE_SIGNAL_LEVEL BIT(1) -+#define SCL_LINE_SIGNAL_LEVEL BIT(0) ++ sts &= ~(AST2600_I2CS_ADDR_INDICATE_MASK); + -+struct ast2600_i3c_swdat_group { -+ u32 dat[NUM_OF_SWDATS_IN_GROUP]; -+ u32 free_pos; -+ int hw_index; -+ struct { -+ u32 set; -+ u32 clr; -+ } mask; -+}; - - struct ast2600_i3c { - struct dw_i3c_master dw; - struct regmap *global_regs; - unsigned int global_idx; - unsigned int sda_pullup; ++ switch (sts) { ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value); ++ /* first address match is address */ ++ byte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff); ++ break; ++ case AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_RX_DMA: ++ byte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &byte_data); ++ break; ++ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_WAIT_TX_DMA: ++ cmd |= AST2600_I2CS_TX_CMD; ++ byte_data = AST2600_I2CC_GET_RX_BUFF(i2c_buff); ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &byte_data); ++ writel(byte_data, i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ break; ++ case AST2600_I2CS_TX_ACK | AST2600_I2CS_WAIT_TX_DMA: ++ cmd |= AST2600_I2CS_TX_CMD; ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &byte_data); ++ writel(byte_data, i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ break; ++ case AST2600_I2CS_STOP: ++ case AST2600_I2CS_STOP | AST2600_I2CS_TX_NAK: ++ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value); ++ break; ++ default: ++ dev_dbg(i2c_bus->dev, "unhandled pkt isr %x\n", sts); ++ break; ++ } ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ writel(sts, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++} + -+ struct ast2600_i3c_swdat_group dat_group[NUM_OF_SWDAT_GROUP]; - }; - -+static u8 even_parity(u8 p) ++static int ast2600_i2c_target_irq(struct ast2600_i2c_bus *i2c_bus) +{ -+ p ^= p >> 4; -+ p &= 0xf; ++ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CS_IER); ++ u32 isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + -+ return (0x9669 >> p) & 1; -+} ++ if (!(isr & ier)) ++ return 0; + -+static inline struct dw_i3c_master * -+to_dw_i3c_master(struct i3c_master_controller *master) -+{ -+ return container_of(master, struct dw_i3c_master, base); -+} ++ /* ++ * Target interrupt coming after Controller packet done ++ * So need handle controller first. ++ * avoid case: Mr Dr P -> S match ++ */ ++ if (readl(i2c_bus->reg_base + AST2600_I2CM_ISR) & AST2600_I2CM_PKT_DONE) ++ return 0; + - static struct ast2600_i3c *to_ast2600_i3c(struct dw_i3c_master *dw) - { - return container_of(dw, struct ast2600_i3c, dw); -@@ -117,9 +194,537 @@ - } - } - -+static void ast2600_i3c_enter_sw_mode(struct dw_i3c_master *dw) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ isr &= ~(AST2600_I2CS_ADDR_MASK); + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_VAL | SDA_IN_SW_MODE_VAL, -+ SCL_IN_SW_MODE_VAL | SDA_IN_SW_MODE_VAL); ++ if (AST2600_I2CS_PKT_DONE & isr) ++ i2c_bus->target_packet_irq(i2c_bus, isr); ++ else ++ i2c_bus->target_byte_irq(i2c_bus, isr); + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN, -+ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN); ++ return 1; +} ++#endif + -+static void ast2600_i3c_exit_sw_mode(struct dw_i3c_master *dw) ++static int ast2600_i2c_setup_dma_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN, 0); -+} ++ cmd |= AST2600_I2CM_PKT_EN; + -+static void ast2600_i3c_toggle_scl_in(struct dw_i3c_master *dw, int count) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ if (xfer_len > AST2600_I2C_DMA_SIZE) ++ xfer_len = AST2600_I2C_DMA_SIZE; ++ else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) ++ cmd |= AST2600_I2CM_STOP_CMD; + -+ for (; count; count--) { -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_VAL, 0); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_VAL, SCL_IN_SW_MODE_VAL); ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++ ++ if (xfer_len) { ++ memcpy(i2c_bus->controller_dma_buf, msg->buf, xfer_len); ++ cmd |= AST2600_I2CM_TX_DMA_EN | AST2600_I2CM_TX_CMD; ++ writel(AST2600_I2CM_SET_TX_DMA_LEN(xfer_len - 1), ++ i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); + } -+} + -+static void ast2600_i3c_gen_internal_stop(struct dw_i3c_master *dw) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_VAL, 0); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_VAL, 0); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_VAL, SCL_IN_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_VAL, SDA_IN_SW_MODE_VAL); ++ return 0; +} + -+static int aspeed_i3c_bus_recovery(struct dw_i3c_master *dw) ++static int ast2700_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ int i, ret = -1; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_SW_MODE_OE, SCL_SW_MODE_OE); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_EN, SCL_OUT_SW_MODE_EN); ++ cmd |= AST2600_I2CM_PKT_EN; + -+ for (i = 0; i < 19; i++) { -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, 0); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); -+ if (readl(dw->regs + PRESENT_STATE) & SDA_LINE_SIGNAL_LEVEL) { -+ ret = 0; -+ break; -+ } -+ } ++ if (xfer_len > i2c_bus->buf_size) ++ xfer_len = i2c_bus->buf_size; ++ else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) ++ cmd |= AST2600_I2CM_STOP_CMD; + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_EN, 0); -+ if (ret) -+ dev_err(&dw->base.dev, "Failed to recover the bus\n"); ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ return ret; -+} ++ if (xfer_len) { ++ u32 wbuf_dword; + -+static void ast2600_i3c_gen_target_reset_pattern(struct dw_i3c_master *dw) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ int i; ++ cmd |= AST2600_I2CM_TX_DMA_EN | AST2600_I2CM_TX_CMD; ++ /* ++ * The controller's buffer register supports dword writes only. ++ * Therefore, write dwords to the buffer register in a 4-byte aligned, ++ * and write the remaining unaligned data at the end. ++ */ ++ for (int i = 0; i < xfer_len; i += 4) { ++ int xfer_cnt = i2c_bus->controller_xfer_cnt + i; + -+ if (dw->base.bus.context == I3C_BUS_CONTEXT_JESD403) { -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_SW_MODE_OE, SCL_SW_MODE_OE); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_EN, SCL_OUT_SW_MODE_EN); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, 0); -+ mdelay(DIV_ROUND_UP(dw->timing.timed_reset_scl_low_ns, -+ 1000000)); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_EN, 0); -+ return; -+ } ++ switch (min(xfer_len - i, 4) % 4) { ++ case 1: ++ wbuf_dword = msg->buf[xfer_cnt]; ++ break; ++ case 2: ++ wbuf_dword = get_unaligned_le16(&msg->buf[xfer_cnt]); ++ break; ++ case 3: ++ wbuf_dword = get_unaligned_le24(&msg->buf[xfer_cnt]); ++ break; ++ default: ++ wbuf_dword = get_unaligned_le32(&msg->buf[xfer_cnt]); ++ break; ++ } ++ writel(wbuf_dword, i2c_bus->buf_base + i); ++ } + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_VAL | SCL_OUT_SW_MODE_VAL, -+ SDA_OUT_SW_MODE_VAL | SCL_OUT_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_SW_MODE_OE | SCL_SW_MODE_OE, -+ SDA_SW_MODE_OE | SCL_SW_MODE_OE); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_EN | SCL_OUT_SW_MODE_EN, -+ SDA_OUT_SW_MODE_EN | SCL_OUT_SW_MODE_EN); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_VAL | SCL_IN_SW_MODE_VAL, -+ SDA_IN_SW_MODE_VAL | SCL_IN_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN, -+ SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, 0); -+ for (i = 0; i < 7; i++) { -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_VAL, 0); -+ regmap_write_bits(i3c->global_regs, -+ AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_VAL, SDA_OUT_SW_MODE_VAL); ++ dev_dbg(i2c_bus->dev, "len : %d\n", xfer_len); ++ writel(AST2600_I2CM_SET_TX_DMA_LEN(xfer_len - 1), ++ i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); + } -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_VAL, 0); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_VAL, SDA_OUT_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_OUT_SW_MODE_EN | SCL_OUT_SW_MODE_EN, 0); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN, 0); -+} -+ -+static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) -+{ -+ u32 state; + -+ /* -+ * Clear the IBI queue to enable the hardware to generate SCL and -+ * begin detecting the T-bit low to stop reading IBI data. -+ */ -+ readl(dw->regs + IBI_QUEUE_STATUS); -+ state = FIELD_GET(CM_TFR_STS, readl(dw->regs + PRESENT_STATE)); -+ if (state == CM_TFR_STS_MASTER_SERV_IBI) -+ return false; ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ return true; ++ return 0; +} + -+static void ast2600_i3c_gen_tbits_in(struct dw_i3c_master *dw) ++static int ast2600_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ bool is_idle; -+ int ret; -+ -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_VAL, SDA_IN_SW_MODE_VAL); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_EN, SDA_IN_SW_MODE_EN); -+ -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_VAL, 0); -+ ret = readx_poll_timeout_atomic(ast2600_i3c_fsm_exit_serv_ibi, dw, -+ is_idle, is_idle, 0, 2000000); -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SDA_IN_SW_MODE_EN, 0); -+ if (ret) -+ dev_err(&dw->base.dev, -+ "Failed to exit the I3C fsm from %lx(MASTER_SERV_IBI): %d", -+ FIELD_GET(CM_TFR_STS, readl(dw->regs + PRESENT_STATE)), -+ ret); -+} ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+static void ast2600_i3c_set_ibi_mdb(struct dw_i3c_master *dw, u8 mdb) -+{ -+ u32 reg; ++ cmd |= AST2600_I2CM_PKT_EN; + -+ reg = readl(dw->regs + DEVICE_CTRL); -+ reg &= ~DEV_CTRL_SLAVE_MDB; -+ reg |= FIELD_PREP(DEV_CTRL_SLAVE_MDB, mdb); -+ writel(reg, dw->regs + DEVICE_CTRL); -+} ++ if (xfer_len > i2c_bus->buf_size) ++ xfer_len = i2c_bus->buf_size; ++ else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) ++ cmd |= AST2600_I2CM_STOP_CMD; + -+static int ast2600_i3c_get_free_hw_pos(struct dw_i3c_master *dw) -+{ -+ if (!(dw->free_pos & GENMASK(dw->maxdevs - 1, 0))) -+ return -ENOSPC; ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ return ffs(dw->free_pos) - 1; -+} ++ if (xfer_len) { ++ u32 wbuf_dword; + -+static void ast2600_i3c_init_swdat(struct dw_i3c_master *dw) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp; -+ int i, j; -+ u32 def_set, def_clr; ++ cmd |= AST2600_I2CM_TX_BUFF_EN | AST2600_I2CM_TX_CMD; ++ /* ++ * The controller's buffer register supports dword writes only. ++ * Therefore, write dwords to the buffer register in a 4-byte aligned, ++ * and write the remaining unaligned data at the end. ++ */ ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) ++ return -EBUSY; ++ for (int i = 0; i < xfer_len; i += 4) { ++ int xfer_cnt = i2c_bus->controller_xfer_cnt + i; + -+ def_clr = DEV_ADDR_TABLE_IBI_ADDR_MASK; -+ def_set = DEV_ADDR_TABLE_MR_REJECT | DEV_ADDR_TABLE_SIR_REJECT; ++ switch (min(xfer_len - i, 4) % 4) { ++ case 1: ++ wbuf_dword = msg->buf[xfer_cnt]; ++ break; ++ case 2: ++ wbuf_dword = get_unaligned_le16(&msg->buf[xfer_cnt]); ++ break; ++ case 3: ++ wbuf_dword = get_unaligned_le24(&msg->buf[xfer_cnt]); ++ break; ++ default: ++ wbuf_dword = get_unaligned_le32(&msg->buf[xfer_cnt]); ++ break; ++ } ++ writel(wbuf_dword, i2c_bus->buf_base + i); ++ } ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) ++ return -EBUSY; ++ writel(AST2600_I2CC_SET_TX_BUF_LEN(xfer_len), ++ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ } + -+ for (i = 0; i < NUM_OF_SWDAT_GROUP; i++) { -+ gp = &i3c->dat_group[i]; -+ gp->hw_index = -1; -+ gp->free_pos = ALL_DATS_IN_GROUP_ARE_FREE; -+ gp->mask.clr = def_clr; -+ gp->mask.set = def_set; ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) ++ return -EBUSY; + -+ for (j = 0; j < NUM_OF_SWDATS_IN_GROUP; j++) -+ gp->dat[j] = 0; -+ } ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ for (i = 0; i < dw->maxdevs; i++) -+ writel(def_set, -+ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, i)); ++ return 0; +} + -+static int ast2600_i3c_set_swdat(struct dw_i3c_master *dw, u8 addr, u32 val) ++static int ast2600_i2c_setup_byte_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; -+ int pos = ADDR_HID(addr); ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len; + -+ if (!(val & DEV_ADDR_TABLE_LEGACY_I2C_DEV)) { -+ /* Calculate DA parity for I3C devices */ -+ val &= ~DEV_ADDR_TABLE_DA_PARITY; -+ val |= FIELD_PREP(DEV_ADDR_TABLE_DA_PARITY, even_parity(addr)); -+ } -+ gp->dat[pos] = val; ++ xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ if (val) { -+ gp->free_pos &= ~BIT(pos); ++ cmd |= AST2600_I2CM_PKT_EN; + -+ /* -+ * reserve the hw dat resource for the first member of the -+ * group. all the members in the group share the same hw dat. -+ */ -+ if (gp->hw_index == -1) { -+ gp->hw_index = ast2600_i3c_get_free_hw_pos(dw); -+ if (gp->hw_index < 0) -+ goto out; ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ dw->free_pos &= ~BIT(gp->hw_index); -+ val &= ~gp->mask.clr; -+ val |= gp->mask.set; -+ writel(val, -+ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, -+ gp->hw_index)); -+ } -+ } else { -+ gp->free_pos |= BIT(pos); ++ if ((i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) && ++ ((i2c_bus->controller_xfer_cnt + 1) == msg->len)) ++ cmd |= AST2600_I2CM_STOP_CMD; + -+ /* -+ * release the hw dat resource if all the members in the group -+ * are free. -+ */ -+ if (gp->free_pos == ALL_DATS_IN_GROUP_ARE_FREE) { -+ writel(gp->mask.set, -+ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, -+ gp->hw_index)); -+ dw->free_pos |= BIT(gp->hw_index); -+ gp->hw_index = -1; -+ } -+ } -+out: -+ return gp->hw_index; -+} ++ if (xfer_len) { ++ cmd |= AST2600_I2CM_TX_CMD; ++ writel(msg->buf[i2c_bus->controller_xfer_cnt], ++ i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ } + -+static u32 ast2600_i3c_get_swdat(struct dw_i3c_master *dw, u8 addr) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ return gp->dat[ADDR_HID(addr)]; ++ return 0; +} + -+static int ast2600_i3c_flush_swdat(struct dw_i3c_master *dw, u8 addr) ++static int ast2600_i2c_setup_dma_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; -+ u32 dat = gp->dat[ADDR_HID(addr)]; -+ int hw_index = gp->hw_index; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ if (!dat || hw_index < 0) -+ return -1; ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_DMA_EN | AST2600_I2CM_RX_CMD; + -+ dat &= ~gp->mask.clr; -+ dat |= gp->mask.set; -+ writel(dat, dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, hw_index)); ++ if (msg->flags & I2C_M_RECV_LEN) { ++ dev_dbg(i2c_bus->dev, "smbus read\n"); ++ xfer_len = 1; ++ } else if (xfer_len > AST2600_I2C_DMA_SIZE) { ++ xfer_len = AST2600_I2C_DMA_SIZE; ++ } else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) { ++ cmd |= CONTROLLER_TRIGGER_LAST_STOP; ++ } ++ ++ writel(AST2600_I2CM_SET_RX_DMA_LEN(xfer_len - 1), i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); ++ ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++ ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + + return 0; +} + -+static int ast2600_i3c_get_swdat_hw_pos(struct dw_i3c_master *dw, u8 addr) ++static int ast2700_i2c_setup_buff_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ return gp->hw_index; -+} ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_DMA_EN | AST2600_I2CM_RX_CMD; + -+static int ast2600_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev, -+ u8 old_dyn_addr) -+{ -+ struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); -+ struct i3c_master_controller *m = i3c_dev_get_master(dev); -+ struct dw_i3c_master *master = to_dw_i3c_master(m); -+ u32 dat = FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_ADDR, dev->info.dyn_addr); ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ if (old_dyn_addr != dev->info.dyn_addr) -+ ast2600_i3c_set_swdat(master, old_dyn_addr, 0); ++ if (msg->flags & I2C_M_RECV_LEN) { ++ dev_dbg(i2c_bus->dev, "smbus read\n"); ++ xfer_len = 1; ++ } else if (xfer_len > i2c_bus->buf_size) { ++ xfer_len = i2c_bus->buf_size; ++ } else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) { ++ cmd |= CONTROLLER_TRIGGER_LAST_STOP; ++ } + -+ ast2600_i3c_set_swdat(master, dev->info.dyn_addr, dat); -+ data->index = ast2600_i3c_get_swdat_hw_pos(master, dev->info.dyn_addr); -+ master->devs[dev->info.dyn_addr].addr = dev->info.dyn_addr; ++ writel(AST2600_I2CM_SET_RX_DMA_LEN(xfer_len - 1), ++ i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + + return 0; +} + -+static int ast2600_i3c_attach_i3c_dev(struct i3c_dev_desc *dev) ++static int ast2600_i2c_setup_buff_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); -+ struct i3c_master_controller *m = i3c_dev_get_master(dev); -+ struct dw_i3c_master *master = to_dw_i3c_master(m); -+ int pos; -+ u8 addr = dev->info.dyn_addr ?: dev->info.static_addr; -+ -+ pos = ast2600_i3c_set_swdat(master, addr, -+ FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_ADDR, addr)); -+ if (pos < 0) -+ return pos; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_BUFF_EN | AST2600_I2CM_RX_CMD; + -+ data->index = ast2600_i3c_get_swdat_hw_pos(master, addr); -+ master->devs[addr].addr = addr; -+ i3c_dev_set_master_data(dev, data); ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ if (master->base.bus.context == I3C_BUS_CONTEXT_JESD403) { -+ dev->info.max_write_ds = 0; -+ dev->info.max_read_ds = 0; ++ if (msg->flags & I2C_M_RECV_LEN) { ++ dev_dbg(i2c_bus->dev, "smbus read\n"); ++ xfer_len = 1; ++ } else if (xfer_len > i2c_bus->buf_size) { ++ xfer_len = i2c_bus->buf_size; ++ } else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) { ++ cmd |= CONTROLLER_TRIGGER_LAST_STOP; + } + ++ writel(AST2600_I2CC_SET_RX_BUF_LEN(xfer_len), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ + return 0; +} + -+static void ast2600_i3c_detach_i3c_dev(struct i3c_dev_desc *dev) ++static int ast2600_i2c_setup_byte_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); -+ struct i3c_master_controller *m = i3c_dev_get_master(dev); -+ struct dw_i3c_master *master = to_dw_i3c_master(m); -+ u8 addr = dev->info.dyn_addr ?: dev->info.static_addr; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; + -+ ast2600_i3c_set_swdat(master, addr, 0); ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_CMD; + -+ i3c_dev_set_master_data(dev, NULL); -+ master->devs[addr].addr = 0; -+ kfree(data); ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++ ++ if (msg->flags & I2C_M_RECV_LEN) { ++ dev_dbg(i2c_bus->dev, "smbus read\n"); ++ } else if ((i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) && ++ ((i2c_bus->controller_xfer_cnt + 1) == msg->len)) { ++ cmd |= CONTROLLER_TRIGGER_LAST_STOP; ++ } ++ ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ ++ return 0; +} + -+static int ast2600_i3c_attach_i2c_dev(struct i2c_dev_desc *dev) ++static int ast2600_i2c_do_start(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); -+ struct i3c_master_controller *m = i2c_dev_get_master(dev); -+ struct dw_i3c_master *master = to_dw_i3c_master(m); -+ int pos; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; + -+ pos = ast2600_i3c_set_swdat(master, dev->addr, -+ DEV_ADDR_TABLE_LEGACY_I2C_DEV | -+ FIELD_PREP(DEV_ADDR_TABLE_STATIC_ADDR, dev->addr)); -+ if (pos < 0) -+ return pos; ++ /* send start */ ++ dev_dbg(i2c_bus->dev, "[%d] %s %d byte%s %s 0x%02x\n", ++ i2c_bus->msgs_index, str_read_write(msg->flags & I2C_M_RD), ++ msg->len, str_plural(msg->len), ++ msg->flags & I2C_M_RD ? "from" : "to", msg->addr); + -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; ++ if (!i2c_bus->setup_rx || !i2c_bus->setup_tx) ++ return -EINVAL; + -+ data->index = ast2600_i3c_get_swdat_hw_pos(master, dev->addr); -+ master->devs[dev->addr].addr = dev->addr; -+ i2c_dev_set_master_data(dev, data); ++ i2c_bus->controller_xfer_cnt = 0; ++ i2c_bus->buf_index = 0; ++ ++ if (msg->flags & I2C_M_RD) ++ return i2c_bus->setup_rx(AST2600_I2CM_START_CMD, i2c_bus); ++ ++ return i2c_bus->setup_tx(AST2600_I2CM_START_CMD, i2c_bus); ++} ++ ++static int ast2700_i2c_irq_err_to_errno(u32 irq_status) ++{ ++ if (irq_status & AST2700_I2CM_ABNORMAL_ACTION) ++ return -EAGAIN; ++ if (irq_status & (AST2600_I2CM_SDA_DL_TO | AST2600_I2CM_SCL_LOW_TO)) ++ return -EBUSY; ++ if (irq_status & (AST2600_I2CM_ABNORMAL)) ++ return -EPROTO; + + return 0; +} + -+static void ast2600_i3c_detach_i2c_dev(struct i2c_dev_desc *dev) ++static void ast2700_i2c_irq_clear(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); -+ struct i3c_master_controller *m = i2c_dev_get_master(dev); -+ struct dw_i3c_master *master = to_dw_i3c_master(m); ++ writel(sts, i2c_bus->reg_base + AST2600_I2CM_ISR); ++} + -+ ast2600_i3c_set_swdat(master, dev->addr, 0); ++static int ast2600_i2c_irq_err_to_errno(u32 irq_status) ++{ ++ if (irq_status & AST2600_I2CM_ARBIT_LOSS) ++ return -EAGAIN; ++ if (irq_status & (AST2600_I2CM_SDA_DL_TO | AST2600_I2CM_SCL_LOW_TO)) ++ return -ETIMEDOUT; ++ if (irq_status & (AST2600_I2CM_ABNORMAL)) ++ return -EPROTO; + -+ i2c_dev_set_master_data(dev, NULL); -+ master->devs[dev->addr].addr = 0; -+ kfree(data); ++ return 0; +} + -+static void ast2600_i3c_set_sir_enabled(struct dw_i3c_master *dw, -+ struct i3c_dev_desc *dev, u8 idx, -+ bool enable) ++static void ast2600_i2c_irq_clear(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp = -+ &i3c->dat_group[ADDR_GRP(dev->info.dyn_addr)]; -+ unsigned long flags; -+ u32 reg; -+ bool global; ++ writel(AST2600_I2CM_PKT_DONE, i2c_bus->reg_base + AST2600_I2CM_ISR); ++} + -+ spin_lock_irqsave(&dw->devs_lock, flags); -+ if (enable) { -+ gp->mask.clr |= DEV_ADDR_TABLE_SIR_REJECT | -+ DEV_ADDR_TABLE_IBI_ADDR_MASK; ++static void ast2600_i2c_controller_packet_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++{ ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len; ++ int i; + -+ gp->mask.set &= ~DEV_ADDR_TABLE_SIR_REJECT; -+ gp->mask.set |= FIELD_PREP(DEV_ADDR_TABLE_IBI_ADDR_MASK, -+ IBI_ADDR_MASK_LAST_3BITS); -+ /* -+ * The ast2600 i3c controller will lock up on receiving 4n+1-byte IBIs -+ * if the PEC is disabled. We have no way to restrict the length of -+ * IBIs sent to the controller, so we need to unconditionally enable -+ * PEC checking, which means we drop a byte of payload data -+ */ -+ gp->mask.set |= DEV_ADDR_TABLE_IBI_PEC; -+ if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) -+ gp->mask.set |= DEV_ADDR_TABLE_IBI_MDB; -+ } else { -+ reg = ast2600_i3c_get_swdat(dw, dev->info.dyn_addr); -+ reg |= DEV_ADDR_TABLE_SIR_REJECT; -+ ast2600_i3c_set_swdat(dw, dev->info.dyn_addr, reg); -+ } ++ i2c_bus->irq_clear(i2c_bus, sts); + -+ reg = readl(dw->regs + IBI_SIR_REQ_REJECT); -+ if (enable) { -+ global = reg == 0xffffffff; -+ reg &= ~BIT(gp->hw_index); -+ } else { -+ int i; -+ bool hj_rejected = !!(readl(dw->regs + DEVICE_CTRL) & -+ DEV_CTRL_HOT_JOIN_NACK); -+ bool ibi_enable = false; ++ sts &= ~(AST2600_I2CM_PKT_DONE | AST2600_I2CM_SW_ISR_MASK); + -+ for (i = 0; i < NUM_OF_SWDATS_IN_GROUP; i++) { -+ if (!(gp->dat[i] & DEV_ADDR_TABLE_SIR_REJECT)) { -+ ibi_enable = true; -+ break; ++ switch (sts) { ++ case AST2600_I2CM_PKT_ERROR: ++ i2c_bus->cmd_err = -EAGAIN; ++ complete(&i2c_bus->cmd_complete); ++ break; ++ case AST2600_I2CM_PKT_ERROR | AST2600_I2CM_TX_NAK: /* a0 fix for issue */ ++ fallthrough; ++ case AST2600_I2CM_PKT_ERROR | AST2600_I2CM_TX_NAK | AST2600_I2CM_NORMAL_STOP: ++ i2c_bus->cmd_err = -ENXIO; ++ complete(&i2c_bus->cmd_complete); ++ break; ++ case AST2600_I2CM_NORMAL_STOP: ++ /* write 0 byte only have stop isr */ ++ i2c_bus->msgs_index++; ++ if (i2c_bus->msgs_index < i2c_bus->msgs_count) { ++ if (ast2600_i2c_do_start(i2c_bus)) { ++ i2c_bus->cmd_err = -EBUSY; ++ complete(&i2c_bus->cmd_complete); + } ++ } else { ++ i2c_bus->cmd_err = i2c_bus->msgs_index; ++ complete(&i2c_bus->cmd_complete); ++ } ++ break; ++ case AST2600_I2CM_TX_ACK: ++ case AST2600_I2CM_TX_ACK | AST2600_I2CM_NORMAL_STOP: ++ if (i2c_bus->mode == DMA_MODE) { ++ xfer_len = AST2600_I2C_GET_TX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CM_DMA_LEN_STS)); ++ } else if (i2c_bus->mode == BUFF_MODE) { ++ if (i2c_bus->version == AST2600) ++ xfer_len = AST2600_I2CC_GET_TX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ else ++ xfer_len = AST2600_I2C_GET_TX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CM_DMA_LEN_STS)); ++ } else { ++ xfer_len = 1; + } + -+ if (!ibi_enable) { -+ reg |= BIT(gp->hw_index); -+ global = (reg == 0xffffffff) && hj_rejected; ++ i2c_bus->controller_xfer_cnt += xfer_len; + -+ gp->mask.set = DEV_ADDR_TABLE_SIR_REJECT; ++ if (i2c_bus->controller_xfer_cnt == msg->len) { ++ i2c_bus->msgs_index++; ++ if (i2c_bus->msgs_index == i2c_bus->msgs_count) { ++ i2c_bus->cmd_err = i2c_bus->msgs_index; ++ complete(&i2c_bus->cmd_complete); ++ } else { ++ if (ast2600_i2c_do_start(i2c_bus)) { ++ i2c_bus->cmd_err = -EBUSY; ++ complete(&i2c_bus->cmd_complete); ++ } ++ } ++ } else { ++ i2c_bus->setup_tx(0, i2c_bus); + } -+ } -+ writel(reg, dw->regs + IBI_SIR_REQ_REJECT); ++ break; ++ case AST2600_I2CM_RX_DONE: ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ /* ++ * Workaround for controller/target packet mode enable rx done stuck issue ++ * When controller go for first read (RX_DONE), target mode will also effect ++ * Then controller will send nack, not operate anymore. ++ */ ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_PKT_MODE_EN) { ++ u32 target_cmd = readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+ if (global) { -+ reg = readl(dw->regs + INTR_STATUS_EN); -+ reg &= ~INTR_IBI_THLD_STAT; -+ if (enable) -+ reg |= INTR_IBI_THLD_STAT; -+ writel(reg, dw->regs + INTR_STATUS_EN); ++ writel(0, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ writel(target_cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ } ++ fallthrough; ++#endif ++ case AST2600_I2CM_RX_DONE | AST2600_I2CM_NORMAL_STOP: ++ /* do next rx */ ++ if (i2c_bus->mode == DMA_MODE) { ++ xfer_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CM_DMA_LEN_STS)); ++ memcpy(&msg->buf[i2c_bus->controller_xfer_cnt], ++ i2c_bus->controller_dma_buf, xfer_len); ++ } else if (i2c_bus->mode == BUFF_MODE) { ++ if (i2c_bus->version == AST2600) { ++ xfer_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CC_BUFF_CTRL)); ++ } else { ++ xfer_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + ++ AST2600_I2CM_DMA_LEN_STS)); ++ } ++ for (i = 0; i < xfer_len; i++) ++ msg->buf[i2c_bus->controller_xfer_cnt + i] = ++ readb(i2c_bus->buf_base + 0x10 + i); ++ } else { ++ xfer_len = 1; ++ msg->buf[i2c_bus->controller_xfer_cnt] = ++ AST2600_I2CC_GET_RX_BUFF(readl(i2c_bus->reg_base + ++ AST2600_I2CC_STS_AND_BUFF)); ++ } + -+ reg = readl(dw->regs + INTR_SIGNAL_EN); -+ reg &= ~INTR_IBI_THLD_STAT; -+ if (enable) -+ reg |= INTR_IBI_THLD_STAT; -+ writel(reg, dw->regs + INTR_SIGNAL_EN); -+ } ++ if (msg->flags & I2C_M_RECV_LEN) { ++ u8 recv_len = 0; + -+ ast2600_i3c_flush_swdat(dw, dev->info.dyn_addr); ++ if (i2c_bus->version == AST2700) { ++ recv_len = AST2700_I2CC_GET_BUFF(readl(i2c_bus->reg_base ++ + BYTE_DATA_LOG)); ++ } else { ++ recv_len = AST2600_I2CC_GET_RX_BUFF(readl(i2c_bus->reg_base ++ + AST2600_I2CC_STS_AND_BUFF)); ++ } + -+ spin_unlock_irqrestore(&dw->devs_lock, flags); -+} ++ msg->len = min_t(unsigned int, recv_len, I2C_SMBUS_BLOCK_MAX); ++ msg->len += ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); ++ msg->flags &= ~I2C_M_RECV_LEN; ++ if (!recv_len) ++ i2c_bus->controller_xfer_cnt = 0; ++ else ++ i2c_bus->controller_xfer_cnt = 1; ++ } else { ++ i2c_bus->controller_xfer_cnt += xfer_len; ++ } + -+static void ast2600_i3c_set_ibi_dev(struct dw_i3c_master *dw, -+ struct i3c_dev_desc *dev) -+{ -+ dw->devs[dev->info.dyn_addr].ibi_dev = dev; ++ if (i2c_bus->controller_xfer_cnt == msg->len) { ++ i2c_bus->msgs_index++; ++ if (i2c_bus->msgs_index == i2c_bus->msgs_count) { ++ i2c_bus->cmd_err = i2c_bus->msgs_index; ++ complete(&i2c_bus->cmd_complete); ++ } else { ++ if (ast2600_i2c_do_start(i2c_bus)) { ++ i2c_bus->cmd_err = -EBUSY; ++ complete(&i2c_bus->cmd_complete); ++ } ++ } ++ } else { ++ i2c_bus->setup_rx(0, i2c_bus); ++ } ++ break; ++ default: ++ dev_dbg(i2c_bus->dev, "unhandled sts %x\n", sts); ++ break; ++ } +} + -+static void ast2600_i3c_unset_ibi_dev(struct dw_i3c_master *dw, -+ struct i3c_dev_desc *dev) ++static int ast2600_i2c_controller_irq(struct ast2600_i2c_bus *i2c_bus) +{ -+ dw->devs[dev->info.dyn_addr].ibi_dev = NULL; -+} ++ u32 sts = readl(i2c_bus->reg_base + AST2600_I2CM_ISR); ++ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CM_IER); ++ u32 ctrl; + -+static struct i3c_dev_desc *ast2600_i3c_get_ibi_dev(struct dw_i3c_master *dw, -+ u8 addr) -+{ -+ return dw->devs[addr].ibi_dev; -+} ++ /* mask un-used isr bits */ ++ sts &= ~AST2600_I2CM_ISR_MASK; + - static const struct dw_i3c_platform_ops ast2600_i3c_ops = { - .init = ast2600_i3c_init, - .set_dat_ibi = ast2600_i3c_set_dat_ibi, -+ .enter_sw_mode = ast2600_i3c_enter_sw_mode, -+ .exit_sw_mode = ast2600_i3c_exit_sw_mode, -+ .toggle_scl_in = ast2600_i3c_toggle_scl_in, -+ .gen_internal_stop = ast2600_i3c_gen_internal_stop, -+ .gen_target_reset_pattern = ast2600_i3c_gen_target_reset_pattern, -+ .gen_tbits_in = ast2600_i3c_gen_tbits_in, -+ .bus_recovery = aspeed_i3c_bus_recovery, -+ .set_ibi_mdb = ast2600_i3c_set_ibi_mdb, -+ .reattach_i3c_dev = ast2600_i3c_reattach_i3c_dev, -+ .attach_i3c_dev = ast2600_i3c_attach_i3c_dev, -+ .detach_i3c_dev = ast2600_i3c_detach_i3c_dev, -+ .attach_i2c_dev = ast2600_i3c_attach_i2c_dev, -+ .detach_i2c_dev = ast2600_i3c_detach_i2c_dev, -+ .get_addr_pos = ast2600_i3c_get_swdat_hw_pos, -+ .flush_dat = ast2600_i3c_flush_swdat, -+ .set_sir_enabled = ast2600_i3c_set_sir_enabled, -+ .set_ibi_dev = ast2600_i3c_set_ibi_dev, -+ .unset_ibi_dev = ast2600_i3c_unset_ibi_dev, -+ .get_ibi_dev = ast2600_i3c_get_ibi_dev, - }; - - static int ast2600_i3c_probe(struct platform_device *pdev) -@@ -156,6 +761,10 @@ - i3c->sda_pullup); - - i3c->dw.platform_ops = &ast2600_i3c_ops; -+ i3c->dw.base.pec_supported = true; ++ if (!i2c_bus->alert_enable) ++ sts &= ~AST2600_I2CM_SMBUS_ALERT; + -+ ast2600_i3c_init_swdat(&i3c->dw); ++ if (sts & AST2600_I2CM_BUS_RECOVER_FAIL) { ++ writel(AST2600_I2CM_BUS_RECOVER_FAIL, i2c_bus->reg_base + AST2600_I2CM_ISR); ++ ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ i2c_bus->cmd_err = -EPROTO; ++ complete(&i2c_bus->cmd_complete); ++ return 1; ++ } + - return dw_i3c_common_probe(&i3c->dw, pdev); - } - -diff --git a/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h b/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h ---- a/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h 2025-12-23 10:16:21.082033373 +0000 -@@ -0,0 +1,413 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+#ifndef VENDOR_ASPEED_H -+#define VENDOR_ASPEED_H ++ if (sts & AST2600_I2CM_BUS_RECOVER) { ++ writel(AST2600_I2CM_BUS_RECOVER, i2c_bus->reg_base + AST2600_I2CM_ISR); ++ i2c_bus->cmd_err = 0; ++ complete(&i2c_bus->cmd_complete); ++ return 1; ++ } + -+/* Aspeed in-house register */ -+#include "linux/bitfield.h" -+#define ast_inhouse_read(r) readl(hci->INHOUSE_regs + (r)) -+#define ast_inhouse_write(r, v) writel(v, hci->INHOUSE_regs + (r)) ++ if (sts & AST2600_I2CM_SMBUS_ALERT) { ++ if (ier & AST2600_I2CM_SMBUS_ALERT) { ++ /* Disable ALT INT */ ++ writel(ier & ~AST2600_I2CM_SMBUS_ALERT, i2c_bus->reg_base + AST2600_I2CM_IER); ++ i2c_handle_smbus_alert(i2c_bus->ara); ++ writel(AST2600_I2CM_SMBUS_ALERT, i2c_bus->reg_base + AST2600_I2CM_ISR); ++ dev_err(i2c_bus->dev, ++ "ast2600_controller_alert_recv bus id %d, Disable Alt, Please Imple\n", ++ i2c_bus->adap.nr); ++ return 1; ++ } ++ } + -+#define ASPEED_I3C_CTRL 0x0 -+#define ASPEED_I3C_CTRL_STOP_QUEUE_PT BIT(31) //Stop the queue read pointer. -+#define ASPEED_I3C_CTRL_INIT BIT(4) -+#define ASPEED_I3C_CTRL_INIT_MODE GENMASK(1, 0) -+#define INIT_MST_MODE 0 -+#define INIT_SEC_MST_MODE 1 -+#define INIT_SLV_MODE 2 ++ /* handle controller abnormal condition */ ++ if (i2c_bus->irq_err_to_errno && i2c_bus->irq_clear) { ++ i2c_bus->cmd_err = i2c_bus->irq_err_to_errno(sts); ++ if (i2c_bus->cmd_err) { ++ i2c_bus->irq_clear(i2c_bus, sts); ++ complete(&i2c_bus->cmd_complete); ++ return 1; ++ } ++ } + -+#define ASPEED_I3C_STS 0x4 -+#define ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS_VALID BIT(23) -+#define ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS GENMASK(22, 16) -+#define ASPEED_I3C_STS_MODE_PURE_SLV BIT(8) -+#define ASPEED_I3C_STS_MODE_SECONDARY_SLV_TO_MST BIT(7) -+#define ASPEED_I3C_STS_MODE_SECONDARY_MST_TO_SLV BIT(6) -+#define ASPEED_I3C_STS_MODE_SECONDARY_SLV BIT(5) -+#define ASPEED_I3C_STS_MODE_SECONDARY_MST BIT(4) -+#define ASPEED_I3C_STS_MODE_PRIMARY_SLV_TO_MST BIT(3) -+#define ASPEED_I3C_STS_MODE_PRIMARY_MST_TO_SLV BIT(2) -+#define ASPEED_I3C_STS_MODE_PRIMARY_SLV BIT(1) -+#define ASPEED_I3C_STS_MODE_PRIMARY_MST BIT(0) ++ if (sts & AST2600_I2CM_PKT_DONE) { ++ ast2600_i2c_controller_packet_irq(i2c_bus, sts); ++ return 1; ++ } + -+#define ASPEED_I3C_DAA_INDEX0 0x10 -+#define ASPEED_I3C_DAA_INDEX1 0x14 -+#define ASPEED_I3C_DAA_INDEX2 0x18 -+#define ASPEED_I3C_DAA_INDEX3 0x1C ++ return 0; ++} + -+#define ASPEED_I3C_AUTOCMD_0 0x20 -+#define ASPEED_I3C_AUTOCMD_1 0x24 -+#define ASPEED_I3C_AUTOCMD_2 0x28 -+#define ASPEED_I3C_AUTOCMD_3 0x2C -+#define ASPEED_I3C_AUTOCMD_4 0x30 -+#define ASPEED_I3C_AUTOCMD_5 0x34 -+#define ASPEED_I3C_AUTOCMD_6 0x38 -+#define ASPEED_I3C_AUTOCMD_7 0x3C ++static irqreturn_t ast2600_i2c_bus_irq(int irq, void *dev_id) ++{ ++ struct ast2600_i2c_bus *i2c_bus = dev_id; + -+#define ASPEED_I3C_AUTOCMD_SEL_0_7 0x40 -+#define ASPEED_I3C_AUTOCMD_SEL_8_15 0x44 -+#define ASPEED_I3C_AUTOCMD_SEL_16_23 0x48 -+#define ASPEED_I3C_AUTOCMD_SEL_24_31 0x4C -+#define ASPEED_I3C_AUTOCMD_SEL_32_39 0x50 -+#define ASPEED_I3C_AUTOCMD_SEL_40_47 0x54 -+#define ASPEED_I3C_AUTOCMD_SEL_48_55 0x58 -+#define ASPEED_I3C_AUTOCMD_SEL_56_63 0x5C -+#define ASPEED_I3C_AUTOCMD_SEL_64_71 0x60 -+#define ASPEED_I3C_AUTOCMD_SEL_72_79 0x64 -+#define ASPEED_I3C_AUTOCMD_SEL_80_87 0x68 -+#define ASPEED_I3C_AUTOCMD_SEL_88_95 0x6C -+#define ASPEED_I3C_AUTOCMD_SEL_96_103 0x70 -+#define ASPEED_I3C_AUTOCMD_SEL_104_111 0x74 -+#define ASPEED_I3C_AUTOCMD_SEL_112_119 0x78 -+#define ASPEED_I3C_AUTOCMD_SEL_120_127 0x7C ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ if (readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL) & AST2600_I2CC_SLAVE_EN) { ++ if (ast2600_i2c_target_irq(i2c_bus)) ++ return IRQ_HANDLED; ++ } ++#endif ++ return IRQ_RETVAL(ast2600_i2c_controller_irq(i2c_bus)); ++} ++ ++static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++{ ++ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(adap); ++ unsigned long timeout; ++ int ret; + -+#define ASPEED_I3C_SLV_CHAR_CTRL 0xA0 -+#define ASPEED_I3C_SLV_CHAR_CTRL_DCR GENMASK(23, 16) -+#define ASPEED_I3C_SLV_CHAR_CTRL_BCR GENMASK(15, 8) -+#define SLV_BCR_DEVICE_ROLE GENMASK(7, 6) -+#define ASPEED_I3C_SLV_CHAR_CTRL_STATIC_ADDR_EN BIT(7) -+#define ASPEED_I3C_SLV_CHAR_CTRL_STATIC_ADDR GENMASK(6, 0) -+#define SLV_PID_HI(x) (((x) >> 32) & GENMASK(15, 0)) -+#define SLV_PID_LO(x) ((x) & GENMASK(31, 0)) -+#define ASPEED_I3C_SLV_PID_LO 0xA4 -+#define ASPEED_I3C_SLV_PID_HI 0xA8 -+#define ASPEED_I3C_SLV_FSM 0xAC -+#define ASPEED_I3C_SLV_CAP_CTRL 0xB0 -+#define ASPEED_I3C_SLV_CAP_CTRL_PEC_EN BIT(31) -+#define ASPEED_I3C_SLV_CAP_CTRL_HAIT_IF_IBI_ERR BIT(30) -+#define ASPEED_I3C_SLV_CAP_CTRL_ACCEPT_CR BIT(16) -+#define ASPEED_I3C_SLV_CAP_CTRL_HJ_REQ BIT(10) -+#define ASPEED_I3C_SLV_CAP_CTRL_MR_REQ BIT(9) -+#define ASPEED_I3C_SLV_CAP_CTRL_IBI_REQ BIT(8) -+#define ASPEED_I3C_SLV_CAP_CTRL_HJ_WAIT BIT(6) -+#define ASPEED_I3C_SLV_CAP_CTRL_MR_WAIT BIT(5) -+#define ASPEED_I3C_SLV_CAP_CTRL_IBI_WAIT BIT(4) -+#define ASPEED_I3C_SLV_CAP_CTRL_NOTSUP_DEF_BYTE BIT(1) -+#define ASPEED_I3C_SLV_CAP_CTRL_I2C_DEV BIT(0) -+/* CCC related registers */ -+#define ASPEED_I3C_SLV_STS1 0xB4 -+#define ASPEED_I3C_SLV_STS1_IBI_PAYLOAD_SIZE GENMASK(31, 24) -+#define ASPEED_I3C_SLV_STS1_RSTACT GENMASK(22, 16) -+/* the parameters for the HDR-DDR Data Transfer Early Termination procedure*/ -+#define ASPEED_I3C_SLV_STS1_ETP_ACK_CAP BIT(15) -+#define ASPEED_I3C_SLV_STS1_ETP_W_REQ BIT(14) -+#define ASPEED_I3C_SLV_STS1_ETP_CRC GENMASK(13, 12) -+#define ASPEED_I3C_SLV_STS1_ENDXFER_CONFIRM BIT(11) -+#define ASPEED_I3C_SLV_STS1_ENTER_TEST_MDOE BIT(8) -+#define ASPEED_I3C_SLV_STS1_HJ_EN BIT(6) -+#define ASPEED_I3C_SLV_STS1_CR_EN BIT(5) -+#define ASPEED_I3C_SLV_STS1_IBI_EN BIT(4) -+#define ASPEED_I3C_SLV_STS1_HJ_DONE BIT(2) -+#define ASPEED_I3C_SLV_STS1_CR_DONE BIT(1) -+#define ASPEED_I3C_SLV_STS1_IBI_DONE BIT(0) -+#define ASPEED_I3C_SLV_STS2 0xB8 -+#define ASPEED_I3C_SLV_STS2_MWL GENMASK(31, 16) -+#define ASPEED_I3C_SLV_STS2_MRL GENMASK(15, 0) -+#define ASPEED_I3C_SLV_STS3_GROUP_ADDR 0xBC -+#define ASPEED_I3C_SLV_STS3_GROUP3_VALID BIT(31) -+#define ASPEED_I3C_SLV_STS3_GROUP3_ADDR GENMASK(30, 24) -+#define ASPEED_I3C_SLV_STS3_GROUP2_VALID BIT(23) -+#define ASPEED_I3C_SLV_STS3_GROUP2_ADDR GENMASK(22, 16) -+#define ASPEED_I3C_SLV_STS3_GROUP1_VALID BIT(15) -+#define ASPEED_I3C_SLV_STS3_GROUP1_ADDR GENMASK(14, 8) -+#define ASPEED_I3C_SLV_STS3_GROUP0_VALID BIT(7) -+#define ASPEED_I3C_SLV_STS3_GROUP0_ADDR GENMASK(6, 0) -+#define ASPEED_I3C_SLV_STS4_RSTACT_TIME 0xC0 -+#define ASPEED_I3C_SLV_STS4_DBG_NET GENMASK(23, 16) -+#define ASPEED_I3C_SLV_STS4_WHOLE_CHIP GENMASK(15, 8) -+#define ASPEED_I3C_SLV_STS4_I3C GENMASK(7, 0) -+#define ASPEED_I3C_SLV_STS5_GETMXDS_RW 0xC4 -+#define ASPEED_I3C_SLV_STS5_MAXWR GENMASK(15, 8) -+#define ASPEED_I3C_SLV_STS5_MAXRD GENMASK(7, 0) -+#define ASPEED_I3C_SLV_STS6_GETMXDS 0xC8 -+#define ASPEED_I3C_SLV_STS6_FORMAT BIT(24) -+#define ASPEED_I3C_SLV_STS6_MAXRD_TURN_H GENMASK(23, 16) -+#define ASPEED_I3C_SLV_STS6_MAXRD_TURN_M GENMASK(15, 8) -+#define ASPEED_I3C_SLV_STS6_MAXRD_TURN_L GENMASK(7, 0) -+#define ASPEED_I3C_SLV_STS7_GETSTATUS 0xCC -+#define ASPEED_I3C_SLV_STS7_PRECR GENMASK(31, 16) -+#define ASPEED_I3C_SLV_STS7_TGT GENMASK(15, 0) -+#define ASPEED_I3C_SLV_STS8_GETCAPS_TGT 0xD0 -+#define ASPEED_I3C_SLV_STS9_GETCAPS_VT_CR 0xD4 -+#define ASPEED_I3C_SLV_STS7_VT GENMASK(31, 16) -+#define ASPEED_I3C_SLV_STS7_CR GENMASK(15, 0) ++ if (!i2c_bus->multi_master && ++ (readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) & AST2600_I2CC_BUS_BUSY_STS)) { ++ ret = ast2600_i2c_recover_bus(i2c_bus); ++ if (ret) ++ return ret; ++ } + -+#define ASPEED_I3C_QUEUE_PTR0 0xD8 -+#define QUEUE_PTR0_TX_R(q) FIELD_GET(GENMASK(24, 20), q) -+#define QUEUE_PTR0_TX_W(q) FIELD_GET(GENMASK(16, 12), q) -+#define QUEUE_PTR0_IBI_R(q) FIELD_GET(GENMASK(11, 10), q) -+#define QUEUE_PTR0_IBI_W(q) FIELD_GET(GENMASK(9, 8), q) -+#define QUEUE_PTR0_RESP_R(q) FIELD_GET(GENMASK(7, 6), q) -+#define QUEUE_PTR0_RESP_W(q) FIELD_GET(GENMASK(5, 4), q) -+#define QUEUE_PTR0_CMD_R(q) FIELD_GET(GENMASK(3, 2), q) -+#define QUEUE_PTR0_CMD_W(q) FIELD_GET(GENMASK(1, 0), q) ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ if (i2c_bus->mode == BUFF_MODE) { ++ if (i2c_bus->target_operate) ++ return -EBUSY; ++ /* disable target isr */ ++ writel(0, i2c_bus->reg_base + AST2600_I2CS_IER); ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR) || i2c_bus->target_operate) { ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); ++ return -EBUSY; ++ } ++ } ++#endif + -+#define ASPEED_I3C_QUEUE_PTR1 0xDC -+#define QUEUE_PTR1_IBI_DATA_R(q) FIELD_GET(GENMASK(28, 24), q) -+#define QUEUE_PTR1_IBI_DATA_W(q) FIELD_GET(GENMASK(20, 16), q) -+#define QUEUE_PTR1_RX_R(q) FIELD_GET(GENMASK(12, 8), q) -+#define QUEUE_PTR1_RX_W(q) FIELD_GET(GENMASK(4, 0), q) ++ i2c_bus->cmd_err = 0; ++ i2c_bus->msgs = msgs; ++ i2c_bus->msgs_index = 0; ++ i2c_bus->msgs_count = num; ++ reinit_completion(&i2c_bus->cmd_complete); ++ ret = ast2600_i2c_do_start(i2c_bus); ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ /* avoid race condication target is wait and controller wait 1st target operate */ ++ if (i2c_bus->mode == BUFF_MODE) ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); ++#endif ++ if (ret) ++ goto controller_out; ++ timeout = wait_for_completion_timeout(&i2c_bus->cmd_complete, i2c_bus->adap.timeout); ++ if (timeout == 0) { ++ u32 ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); + -+#define ASPEED_I3C_INTR_STATUS 0xE0 -+#define ASPEED_I3C_INTR_STATUS_ENABLE 0xE4 -+#define ASPEED_I3C_INTR_SIGNAL_ENABLE 0xE8 -+#define ASPEED_I3C_INTR_FORCE 0xEC -+#define ASPEED_I3C_INTR_I2C_SDA_STUCK_LOW BIT(14) -+#define ASPEED_I3C_INTR_I3C_SDA_STUCK_HIGH BIT(13) -+#define ASPEED_I3C_INTR_I3C_SDA_STUCK_LOW BIT(12) -+#define ASPEED_I3C_INTR_MST_INTERNAL_DONE BIT(10) -+#define ASPEED_I3C_INTR_MST_DDR_READ_DONE BIT(9) -+#define ASPEED_I3C_INTR_MST_DDR_WRITE_DONE BIT(8) -+#define ASPEED_I3C_INTR_MST_IBI_DONE BIT(7) -+#define ASPEED_I3C_INTR_MST_READ_DONE BIT(6) -+#define ASPEED_I3C_INTR_MST_WRITE_DONE BIT(5) -+#define ASPEED_I3C_INTR_MST_DAA_DONE BIT(4) -+#define ASPEED_I3C_INTR_SLV_SCL_STUCK BIT(1) -+#define ASPEED_I3C_INTR_TGRST BIT(0) ++ dev_dbg(i2c_bus->dev, "timeout isr[%x], sts[%x]\n", ++ readl(i2c_bus->reg_base + AST2600_I2CM_ISR), ++ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); ++ writel(ctrl & ~AST2600_I2CC_MASTER_EN, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); + -+#define ASPEED_I3C_INTR_SUM_STATUS 0xF0 -+#define ASPEED_INTR_SUM_INHOUSE BIT(3) -+#define ASPEED_INTR_SUM_RHS BIT(2) -+#define ASPEED_INTR_SUM_PIO BIT(1) -+#define ASPEED_INTR_SUM_CAP BIT(0) ++ /* ++ * A slave holding SCL low can stall the transfer and trigger ++ * a master timeout. In multi-master mode, attempt bus recovery ++ * if the bus is still busy. ++ */ ++ if (i2c_bus->multi_master && !i2c_bus->target_operate && ++ (readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) & ++ AST2600_I2CC_BUS_BUSY_STS)) ++ ast2600_i2c_recover_bus(i2c_bus); ++ ret = -ETIMEDOUT; ++ } else { ++ ret = i2c_bus->cmd_err; ++ } + -+#define ASPEED_I3C_INTR_RENEW 0xF4 ++ dev_dbg(i2c_bus->dev, "bus%d-m: %d end\n", i2c_bus->adap.nr, i2c_bus->cmd_err); + -+/* Aspeed Phy register */ -+#define ast_phy_read(r) readl(hci->PHY_regs + (r)) -+#define ast_phy_write(r, v) writel(v, hci->PHY_regs + (r)) ++controller_out: ++ return ret; ++} + -+#define PHY_SW_FORCE_CTRL 0x4 -+#define PHY_SW_FORCE_CTRL_SCL_IN_EN BIT(31) -+#define PHY_SW_FORCE_CTRL_SCL_OUT_EN BIT(30) -+#define PHY_SW_FORCE_CTRL_SCL_OE_EN BIT(29) -+#define PHY_SW_FORCE_CTRL_SCL_PU_EN BIT(28) -+#define PHY_SW_FORCE_CTRL_SDA_IN_EN BIT(27) -+#define PHY_SW_FORCE_CTRL_SDA_OUT_EN BIT(26) -+#define PHY_SW_FORCE_CTRL_SDA_OE_EN BIT(25) -+#define PHY_SW_FORCE_CTRL_SDA_PU_EN BIT(24) -+#define PHY_SW_FORCE_CTRL_SCL_IN_VAL BIT(13) -+#define PHY_SW_FORCE_CTRL_SCL_OUT_VAL BIT(12) -+#define PHY_SW_FORCE_CTRL_SCL_OE_VAL BIT(11) -+#define PHY_SW_FORCE_CTRL_SCL_PU_VAL GENMASK(10, 8) -+#define PHY_SW_FORCE_CTRL_SDA_IN_VAL BIT(5) -+#define PHY_SW_FORCE_CTRL_SDA_OUT_VAL BIT(4) -+#define PHY_SW_FORCE_CTRL_SDA_OE_VAL BIT(3) -+#define PHY_SW_FORCE_CTRL_SDA_PU_VAL GENMASK(2, 0) ++static int ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) ++{ ++ struct platform_device *pdev = to_platform_device(i2c_bus->dev); ++ u32 fun_ctrl = AST2600_I2CC_BUS_AUTO_RELEASE | AST2600_I2CC_MASTER_EN; + -+/* I2C FM: 400K */ -+#define PHY_I2C_FM_CTRL0 0x8 -+#define PHY_I2C_FM_CTRL0_CAS GENMASK(25, 16) -+#define PHY_I2C_FM_CTRL0_SU_STO GENMASK(9, 0) -+#define PHY_I2C_FM_CTRL1 0xC -+#define PHY_I2C_FM_CTRL1_SCL_H GENMASK(25, 16) -+#define PHY_I2C_FM_CTRL1_SCL_L GENMASK(9, 0) -+#define PHY_I2C_FM_CTRL2 0x10 -+#define PHY_I2C_FM_CTRL2_ACK_H GENMASK(25, 16) -+#define PHY_I2C_FM_CTRL2_ACK_L GENMASK(9, 0) -+#define PHY_I2C_FM_CTRL3 0x14 -+#define PHY_I2C_FM_CTRL3_HD_DAT GENMASK(25, 16) -+#define PHY_I2C_FM_CTRL3_AHD_DAT GENMASK(9, 0) ++ /* I2C Reset */ ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); + -+#define PHY_I2C_FM_DEFAULT_CAS_NS 1130 -+#define PHY_I2C_FM_DEFAULT_SU_STO_NS 1370 -+#define PHY_I2C_FM_DEFAULT_SCL_H_NS 1130 -+#define PHY_I2C_FM_DEFAULT_SCL_L_NS 1370 -+#define PHY_I2C_FM_DEFAULT_HD_DAT 10 -+#define PHY_I2C_FM_DEFAULT_AHD_DAT 10 ++ if (!i2c_bus->multi_master) ++ fun_ctrl |= AST2600_I2CC_MULTI_MASTER_DIS; + -+/* I2C FMP: 1M */ -+#define PHY_I2C_FMP_CTRL0 0x18 -+#define PHY_I2C_FMP_CTRL0_CAS GENMASK(25, 16) -+#define PHY_I2C_FMP_CTRL0_SU_STO GENMASK(9, 0) -+#define PHY_I2C_FMP_CTRL1 0x1C -+#define PHY_I2C_FMP_CTRL1_SCL_H GENMASK(25, 16) -+#define PHY_I2C_FMP_CTRL1_SCL_L GENMASK(9, 0) -+#define PHY_I2C_FMP_CTRL2 0x20 -+#define PHY_I2C_FMP_CTRL2_ACK_H GENMASK(25, 16) -+#define PHY_I2C_FMP_CTRL2_ACK_L GENMASK(9, 0) -+#define PHY_I2C_FMP_CTRL3 0x24 -+#define PHY_I2C_FMP_CTRL3_HD_DAT GENMASK(25, 16) -+#define PHY_I2C_FMP_CTRL3_AHD_DAT GENMASK(9, 0) ++ /* I2C manual minimum SCL high */ ++ if (device_property_read_u32(&pdev->dev, "manual-min-high", ++ &i2c_bus->manual_min_high)) ++ i2c_bus->manual_min_high = 0; + -+#define PHY_I2C_FMP_DEFAULT_CAS_NS 380 -+#define PHY_I2C_FMP_DEFAULT_SU_STO_NS 620 -+#define PHY_I2C_FMP_DEFAULT_SCL_H_NS 380 -+#define PHY_I2C_FMP_DEFAULT_SCL_L_NS 620 -+#define PHY_I2C_FMP_DEFAULT_HD_DAT 10 -+#define PHY_I2C_FMP_DEFAULT_AHD_DAT 10 ++ /* I2C manual data hold */ ++ if (device_property_read_u32(&pdev->dev, "manual-data-hold", ++ &i2c_bus->manual_data_hold)) ++ i2c_bus->manual_data_hold = 0; + -+/* I3C OD */ -+#define PHY_I3C_OD_CTRL0 0x28 -+#define PHY_I3C_OD_CTRL0_CAS GENMASK(25, 16) -+#define PHY_I3C_OD_CTRL0_CBP GENMASK(9, 0) -+#define PHY_I3C_OD_CTRL1 0x2C -+#define PHY_I3C_OD_CTRL1_SCL_H GENMASK(25, 16) -+#define PHY_I3C_OD_CTRL1_SCL_L GENMASK(9, 0) -+#define PHY_I3C_OD_CTRL2 0x30 -+#define PHY_I3C_OD_CTRL2_ACK_H GENMASK(25, 16) -+#define PHY_I3C_OD_CTRL2_ACK_L GENMASK(9, 0) -+#define PHY_I3C_OD_CTRL3 0x34 -+#define PHY_I3C_OD_CTRL3_HD_DAT GENMASK(25, 16) -+#define PHY_I3C_OD_CTRL3_AHD_DAT GENMASK(9, 0) ++ /* I2C Debounce level */ ++ if (i2c_bus->version != AST2600) { ++ if (!device_property_read_u32(&pdev->dev, "debounce-level", ++ &i2c_bus->debounce_level)) { ++ u32 debounce_level = 0; + -+#define PHY_I3C_OD_DEFAULT_CAS_NS 40 -+#define PHY_I3C_OD_DEFAULT_CBP_NS 40 -+#define PHY_I3C_OD_DEFAULT_SCL_H_NS 380 -+#define PHY_I3C_OD_DEFAULT_SCL_L_NS 620 -+#define PHY_I3C_OD_DEFAULT_HD_DAT 10 -+#define PHY_I3C_OD_DEFAULT_AHD_DAT 10 ++ /* AST2700 support manual debounce setting */ ++ if (i2c_bus->version == AST2700) { ++ if (i2c_bus->debounce_level > AST2700_DEBOUNCE_LEVEL_MAX) ++ i2c_bus->debounce_level = AST2700_DEBOUNCE_LEVEL_MAX; ++ if (i2c_bus->debounce_level < AST2700_DEBOUNCE_LEVEL_MIN) ++ i2c_bus->debounce_level = AST2700_DEBOUNCE_LEVEL_MIN; ++ } + -+/* I3C PP SDR0 */ -+#define PHY_I3C_SDR0_CTRL0 0x38 -+#define PHY_I3C_SDR0_CTRL0_SCL_H GENMASK(25, 16) -+#define PHY_I3C_SDR0_CTRL0_SCL_L GENMASK(9, 0) -+#define PHY_I3C_SDR0_CTRL1 0x3C -+#define PHY_I3C_SDR0_CTRL1_TBIT_H GENMASK(25, 16) -+#define PHY_I3C_SDR0_CTRL1_TBIT_L GENMASK(9, 0) -+#define PHY_I3C_SDR0_CTRL2 0x40 -+#define PHY_I3C_SDR0_CTRL2_HD_PP GENMASK(25, 16) -+#define PHY_I3C_SDR0_CTRL2_TBIT_HD_PP GENMASK(9, 0) ++ debounce_level = readl(i2c_bus->reg_base + MSIC2_CONFIG) ++ & ~(AST2700_DEBOUNCE_MASK); + -+/* 1MHz */ -+#define PHY_I3C_SDR0_DEFAULT_SCL_H_NS 380 -+#define PHY_I3C_SDR0_DEFAULT_SCL_L_NS 620 -+#define PHY_I3C_SDR0_DEFAULT_TBIT_H_NS 380 -+#define PHY_I3C_SDR0_DEFAULT_TBIT_L_NS 620 -+#define PHY_I3C_SDR0_DEFAULT_HD_PP_NS 10 -+#define PHY_I3C_SDR0_DEFAULT_TBIT_HD_PP_NS 10 ++ debounce_level |= i2c_bus->debounce_level; ++ writel(debounce_level, i2c_bus->reg_base + MSIC2_CONFIG); + -+#define PHY_I3C_CTRL0_OFFSET 0x0 -+#define PHY_I3C_CTRL1_OFFSET 0x4 -+#define PHY_I3C_CTRL2_OFFSET 0x8 -+/* I3C PP SDR1 */ -+#define PHY_I3C_SDR1_CTRL0 0x44 -+#define PHY_I3C_SDR1_CTRL0_SCL_H GENMASK(25, 16) -+#define PHY_I3C_SDR1_CTRL0_SCL_L GENMASK(9, 0) -+#define PHY_I3C_SDR1_CTRL1 0x48 -+#define PHY_I3C_SDR1_CTRL1_TBIT_H GENMASK(25, 16) -+#define PHY_I3C_SDR1_CTRL1_TBIT_L GENMASK(9, 0) -+#define PHY_I3C_SDR1_CTRL2 0x4C -+#define PHY_I3C_SDR1_CTRL2_HD_PP GENMASK(25, 16) -+#define PHY_I3C_SDR1_CTRL2_TBIT_HD_PP GENMASK(9, 0) -+/* I3C PP SDR2 */ -+#define PHY_I3C_SDR2_CTRL0 0x50 -+#define PHY_I3C_SDR2_CTRL0_SCL_H GENMASK(25, 16) -+#define PHY_I3C_SDR2_CTRL0_SCL_L GENMASK(9, 0) -+#define PHY_I3C_SDR2_CTRL1 0x54 -+#define PHY_I3C_SDR2_CTRL1_TBIT_H GENMASK(25, 16) -+#define PHY_I3C_SDR2_CTRL1_TBIT_L GENMASK(9, 0) -+#define PHY_I3C_SDR2_CTRL2 0x58 -+#define PHY_I3C_SDR2_CTRL2_HD_PP GENMASK(25, 16) -+#define PHY_I3C_SDR2_CTRL2_TBIT_HD_PP GENMASK(9, 0) -+/* I3C PP SDR3 */ -+#define PHY_I3C_SDR3_CTRL0 0x5C -+#define PHY_I3C_SDR3_CTRL0_SCL_H GENMASK(25, 16) -+#define PHY_I3C_SDR3_CTRL0_SCL_L GENMASK(9, 0) -+#define PHY_I3C_SDR3_CTRL1 0x60 -+#define PHY_I3C_SDR3_CTRL1_TBIT_H GENMASK(25, 16) -+#define PHY_I3C_SDR3_CTRL1_TBIT_L GENMASK(9, 0) -+#define PHY_I3C_SDR3_CTRL2 0x64 -+#define PHY_I3C_SDR3_CTRL2_HD_PP GENMASK(25, 16) -+#define PHY_I3C_SDR3_CTRL2_TBIT_HD_PP GENMASK(9, 0) -+/* I3C PP SDR4 */ -+#define PHY_I3C_SDR4_CTRL0 0x68 -+#define PHY_I3C_SDR4_CTRL0_SCL_H GENMASK(25, 16) -+#define PHY_I3C_SDR4_CTRL0_SCL_L GENMASK(9, 0) -+#define PHY_I3C_SDR4_CTRL1 0x6C -+#define PHY_I3C_SDR4_CTRL1_TBIT_H GENMASK(25, 16) -+#define PHY_I3C_SDR4_CTRL1_TBIT_L GENMASK(9, 0) -+#define PHY_I3C_SDR4_CTRL2 0x70 -+#define PHY_I3C_SDR4_CTRL2_HD_PP GENMASK(25, 16) -+#define PHY_I3C_SDR4_CTRL2_TBIT_HD_PP GENMASK(9, 0) -+/* I3C PP DDR */ -+#define PHY_I3C_DDR_CTRL0 0x74 -+#define PHY_I3C_DDR_CTRL0_SCL_H GENMASK(25, 16) -+#define PHY_I3C_DDR_CTRL0_SCL_L GENMASK(9, 0) -+#define PHY_I3C_DDR_CTRL1 0x78 -+#define PHY_I3C_DDR_CTRL1_TBIT_H GENMASK(25, 16) -+#define PHY_I3C_DDR_CTRL1_TBIT_L GENMASK(9, 0) -+#define PHY_I3C_DDR_CTRL2 0x7C -+#define PHY_I3C_DDR_CTRL2_HD_PP GENMASK(25, 16) -+#define PHY_I3C_DDR_CTRL2_TBIT_HD_PP GENMASK(9, 0) ++ fun_ctrl |= AST2700_I2CC_MANUAL_DEBOUNCE; ++ } ++ } + -+/* 1MHz */ -+#define PHY_I3C_DDR_DEFAULT_SCL_H_NS 380 -+#define PHY_I3C_DDR_DEFAULT_SCL_L_NS 620 -+#define PHY_I3C_DDR_DEFAULT_TBIT_H_NS 380 -+#define PHY_I3C_DDR_DEFAULT_TBIT_L_NS 620 -+#define PHY_I3C_DDR_DEFAULT_HD_PP_NS 10 -+#define PHY_I3C_DDR_DEFAULT_TBIT_HD_PP_NS 10 ++ /* Enable Controller Mode */ ++ writel(fun_ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ /* disable target address */ ++ writel(0, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); + -+#define PHY_I3C_SR_P_PREPARE_CTRL 0x80 -+#define PHY_I3C_SR_P_PREPARE_CTRL_HD GENMASK(25, 16) -+#define PHY_I3C_SR_P_PREPARE_CTRL_SCL_L GENMASK(9, 0) -+#define PHY_I3C_SR_P_DEFAULT_HD_NS 16 -+#define PHY_I3C_SR_P_DEFAULT_SCL_L_NS 40 ++ if (i2c_bus->version == AST2700 && i2c_bus->mode == BUFF_MODE) { ++ writel(0x00, i2c_bus->reg_base + AST2600_I2CM_TX_DMA); ++ writel(0x00, i2c_bus->reg_base + AST2600_I2CM_TX_DMA_H); ++ writel(0x10, i2c_bus->reg_base + AST2600_I2CM_RX_DMA); ++ writel(0x00, i2c_bus->reg_base + AST2600_I2CM_RX_DMA_H); ++ writel(0x20, i2c_bus->reg_base + AST2600_I2CS_TX_DMA); ++ writel(0x00, i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); ++ writel(0x30, i2c_bus->reg_base + AST2600_I2CS_RX_DMA); ++ writel(0x00, i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); ++ } + -+#define PHY_PULLUP_EN 0x98 -+#define PHY_PULLUP_EN_SCL GENMASK(14, 12) -+#define PHY_PULLUP_EN_SDA GENMASK(10, 8) -+#define PHY_PULLUP_EN_DDR_SCL GENMASK(6, 4) -+#define PHY_PULLUP_EN_DDR_SDA GENMASK(2, 0) ++ /* Set AC Timing */ ++ i2c_bus->ac_timing_config(i2c_bus); + -+#define PHY_I3C_OD_CTRL4 0xD8 -+// SDA drive high (push-pull) time After tCBP -+#define PHY_I3C_OD_CTRL4_DAP GENMASK(26, 16) -+#define PHY_I3C_OD_DEFAULT_DAP_NS 12 ++ if (i2c_bus->mode == DMA_MODE) { ++ i2c_bus->controller_dma_buf = ++ dmam_alloc_coherent(i2c_bus->dev, AST2600_I2C_DMA_SIZE, ++ &i2c_bus->controller_dma_addr, GFP_KERNEL); ++ if (!i2c_bus->controller_dma_buf) ++ return -ENOMEM; ++ writel(lower_32_bits(i2c_bus->controller_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CM_TX_DMA); ++ writel(upper_32_bits(i2c_bus->controller_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CM_TX_DMA_H); ++ writel(lower_32_bits(i2c_bus->controller_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CM_RX_DMA); ++ writel(upper_32_bits(i2c_bus->controller_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CM_RX_DMA_H); ++ } + -+static inline unsigned int aspeed_get_avail_tx_entries(struct i3c_hci *hci) -+{ -+ unsigned int queue_ptr, entries; ++ /* Clear Interrupt */ ++ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR); + -+ queue_ptr = ast_inhouse_read(ASPEED_I3C_QUEUE_PTR0); -+ if (QUEUE_PTR0_TX_W(queue_ptr) >= QUEUE_PTR0_TX_R(queue_ptr)) -+ entries = 0x20 - (QUEUE_PTR0_TX_W(queue_ptr) - -+ QUEUE_PTR0_TX_R(queue_ptr)); ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ /* for memory buffer initial */ ++ if (i2c_bus->mode == DMA_MODE) { ++ i2c_bus->target_dma_buf = ++ dmam_alloc_coherent(i2c_bus->dev, I2C_TARGET_MSG_BUF_SIZE, ++ &i2c_bus->target_dma_addr, GFP_KERNEL); ++ if (!i2c_bus->target_dma_buf) ++ return -ENOMEM; ++ } ++ ++ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CS_ISR); ++ ++ if (i2c_bus->mode == BYTE_MODE) ++ writel(GENMASK(15, 0), i2c_bus->reg_base + AST2600_I2CS_IER); + else -+ entries = QUEUE_PTR0_TX_R(queue_ptr) - QUEUE_PTR0_TX_W(queue_ptr); ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); ++#endif + -+ return entries; ++ return 0; +} + -+static inline unsigned int aspeed_get_received_rx_entries(struct i3c_hci *hci) ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++static int ast2600_i2c_reg_target(struct i2c_client *client) +{ -+ unsigned int queue_ptr, entries; ++ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter); ++ u32 cmd = TARGET_TRIGGER_CMD; ++ u32 target_addr = readl(i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); ++ u32 ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ bool target_reg = false; ++ u8 i = 0; + -+ queue_ptr = ast_inhouse_read(ASPEED_I3C_QUEUE_PTR1); -+ if (QUEUE_PTR1_RX_W(queue_ptr) >= QUEUE_PTR1_RX_R(queue_ptr)) -+ entries = QUEUE_PTR1_RX_W(queue_ptr) - QUEUE_PTR1_RX_R(queue_ptr); -+ else -+ entries = 0x20 - (QUEUE_PTR1_RX_R(queue_ptr) - -+ QUEUE_PTR1_RX_W(queue_ptr)); ++ /* check target client input and target counts*/ ++ if (!client || i2c_bus->target_attached == AST2600_I2C_TARGET_COUNT) ++ return -EINVAL; + -+ return entries; -+} ++ /* check duplicate address */ ++ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { ++ if (i2c_bus->multi_target[i]) { ++ if (i2c_bus->multi_target[i]->addr == client->addr) { ++ dev_dbg(i2c_bus->dev, "duplicate address [%x] on %d\n", ++ client->addr, i); ++ return -EINVAL; ++ } ++ } ++ } + -+static inline unsigned int aspeed_get_i3c_revision_id(struct i3c_hci *hci) -+{ -+ return FIELD_GET(GENMASK(23, 16), hci->vendor_product_id); -+} ++ /* assign the target address into array */ ++ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { ++ if (!i2c_bus->multi_target[i]) { ++ i2c_bus->multi_target[i] = client; ++ target_reg = true; ++ dev_dbg(i2c_bus->dev, "reg [%x] on %d\n", client->addr, i); + -+static inline void aspeed_i3c_ccc_handler(struct i3c_hci *hci, u8 ccc) -+{ -+ u32 reg; -+ u8 dynamic_addr; ++ /* set target addr by index */ ++ switch (i) { ++ case 0: ++ target_addr &= ~(AST2600_I2CS_ADDR1_MASK); ++ target_addr |= (AST2600_I2CS_ADDR1(client->addr) ++ | AST2600_I2CS_ADDR1_ENABLE); ++ break; ++ case 1: ++ target_addr &= ~(AST2600_I2CS_ADDR2_MASK); ++ target_addr |= (AST2600_I2CS_ADDR2(client->addr) ++ | AST2600_I2CS_ADDR2_ENABLE); ++ break; ++ case 2: ++ target_addr &= ~(AST2600_I2CS_ADDR3_MASK); ++ target_addr |= (AST2600_I2CS_ADDR3(client->addr) ++ | AST2600_I2CS_ADDR3_ENABLE); ++ break; ++ } + -+ switch (ccc) { -+ case I3C_CCC_RSTDAA(true): -+ case I3C_CCC_RSTDAA(false): -+ hci->master.this->info.dyn_addr = 0; -+ break; -+ case I3C_CCC_ENTDAA: -+ case I3C_CCC_SETDASA: -+ case I3C_CCC_SETNEWDA: -+ case I3C_CCC_SETAASA: -+ reg = ast_inhouse_read(ASPEED_I3C_STS); -+ if (reg & ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS_VALID) { -+ dynamic_addr = FIELD_GET(ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS, reg); -+ hci->master.this->info.dyn_addr = dynamic_addr; ++ /* Set target addr. */ ++ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); ++ break; + } -+ break; + } -+} + -+#endif -diff --git a/drivers/i3c/mctp/Kconfig b/drivers/i3c/mctp/Kconfig ---- a/drivers/i3c/mctp/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i3c/mctp/Kconfig 2025-12-23 10:16:19.325062821 +0000 -@@ -0,0 +1,23 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+config I3C_MCTP -+ tristate "I3C Controller MCTP driver" -+ depends on I3C -+help -+ Say yes here to enable the I3C MCTP driver for I3C HW that is -+ configured as an I3C Controller Device on the I3C Bus. -+ -+config I3C_MCTP_HDR_DDR -+ bool "transfer with HDR-DDR mode" -+ depends on I3C_MCTP -+ default n -+ help -+ Say yes here to use the HDR-DDR mode as default to transfer data if -+ the device support it. -+ -+config I3C_TARGET_MCTP -+ tristate "I3C Target MCTP driver" -+ depends on I3C -+ select CRC8 -+help -+ Say yes here to enable the I3C MCTP driver for I3C HW that is -+ configured as an I3C Target Device on the I3C Bus. -diff --git a/drivers/i3c/mctp/Makefile b/drivers/i3c/mctp/Makefile ---- a/drivers/i3c/mctp/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i3c/mctp/Makefile 2025-12-23 10:16:19.325062821 +0000 -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+obj-$(CONFIG_I3C_MCTP) += i3c-mctp.o -+obj-$(CONFIG_I3C_TARGET_MCTP) += i3c-target-mctp.o -diff --git a/drivers/i3c/mctp/i3c-mctp.c b/drivers/i3c/mctp/i3c-mctp.c ---- a/drivers/i3c/mctp/i3c-mctp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i3c/mctp/i3c-mctp.c 2025-12-23 10:16:19.325062821 +0000 -@@ -0,0 +1,697 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright (C) 2022 Intel Corporation.*/ ++ /* don't reg target */ ++ if (!target_reg) ++ return -EINVAL; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ dev_dbg(i2c_bus->dev, "target addr %x\n", client->addr); ++ ++ /* turn on target mode */ ++ if (!(ctrl & AST2600_I2CC_SLAVE_EN)) { ++ writel(ctrl | AST2600_I2CC_SLAVE_EN, ++ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ } ++ ++ /* trigger rx buffer */ ++ if (i2c_bus->mode == DMA_MODE) { ++ cmd |= AST2600_I2CS_RX_DMA_EN; ++ writel(lower_32_bits(i2c_bus->target_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CS_RX_DMA); ++ writel(upper_32_bits(i2c_bus->target_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); ++ writel(lower_32_bits(i2c_bus->target_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CS_TX_DMA); ++ writel(upper_32_bits(i2c_bus->target_dma_addr), ++ i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ } else if (i2c_bus->mode == BUFF_MODE) { ++ cmd = TARGET_TRIGGER_CMD; ++ if (i2c_bus->version == AST2700) { ++ writel(AST2600_I2CS_SET_RX_DMA_LEN(i2c_bus->buf_size), ++ i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); ++ cmd |= AST2600_I2CS_RX_DMA_EN; ++ } ++ } else { ++ cmd &= ~AST2600_I2CS_PKT_MODE_EN; ++ } + -+#include -+#include ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+#include ++ i2c_bus->target_attached++; ++ return 0; ++} + -+#define I3C_MCTP_MINORS 32 -+#define CCC_DEVICE_STATUS_PENDING_INTR(x) (((x) & GENMASK(3, 0)) >> 0) -+#define POLLING_TIMEOUT_MS 50 -+#define MCTP_INTERRUPT_NUMBER 1 -+#define RX_RING_COUNT 16 -+#define I3C_MCTP_MIN_TRANSFER_SIZE 69 -+#define I3C_MCTP_IBI_PAYLOAD_SIZE 2 ++static int ast2600_i2c_unreg_target(struct i2c_client *client) ++{ ++ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter); ++ u32 target_addr = readl(i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); ++ bool target_unreg = false; ++ u8 i = 0; + -+struct i3c_mctp { -+ struct i3c_device *i3c; -+ struct cdev cdev; -+ struct device *dev; -+ struct delayed_work polling_work; -+ struct platform_device *i3c_peci; -+ int id; -+ /* -+ * Restrict an access to the /dev descriptor to one -+ * user at a time. -+ */ -+ spinlock_t device_file_lock; -+ int device_open; -+ /* Currently only one userspace client is supported */ -+ struct i3c_mctp_client *default_client; -+ struct i3c_mctp_client *peci_client; -+ u16 max_read_len; -+ u16 max_write_len; -+}; ++ /* check target client input and salve counts*/ ++ if (!client || i2c_bus->target_attached == 0) ++ return -EINVAL; + -+struct i3c_mctp_client { -+ struct i3c_mctp *priv; -+ struct ptr_ring rx_queue; -+ wait_queue_head_t wait_queue; -+}; ++ /* remove the target call back from array */ ++ for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { ++ if (i2c_bus->multi_target[i]) { ++ if (i2c_bus->multi_target[i]->addr == client->addr) { ++ i2c_bus->multi_target[i] = NULL; ++ target_unreg = true; ++ dev_dbg(i2c_bus->dev, "un-reg [%x] from %d\n", client->addr, i); ++ /* remove target addr by index */ ++ target_addr &= ~(0xff << 8 * i); ++ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); ++ break; ++ } ++ } ++ } + -+static struct class *i3c_mctp_class; -+static dev_t i3c_mctp_devt; -+static DEFINE_IDA(i3c_mctp_ida); ++ /* don't un-reg target */ ++ if (!target_unreg) ++ return -EINVAL; + -+static struct kmem_cache *packet_cache; ++ i2c_bus->target_attached--; + -+/** -+ * i3c_mctp_packet_alloc() - allocates i3c_mctp_packet -+ * -+ * @flags: the type of memory to allocate -+ * -+ * Allocates i3c_mctp_packet via slab allocation -+ * Return: pointer to the packet, NULL if some error occurred -+ */ -+void *i3c_mctp_packet_alloc(gfp_t flags) -+{ -+ return kmem_cache_alloc(packet_cache, flags); ++ /* Turn off target mode */ ++ if (i2c_bus->target_attached == 0x0) { ++ writel(~AST2600_I2CC_SLAVE_EN & readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL), ++ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ } ++ ++ return 0; +} -+EXPORT_SYMBOL_GPL(i3c_mctp_packet_alloc); ++#endif + -+/** -+ * i3c_mctp_packet_free() - frees i3c_mctp_packet -+ * -+ * @packet: pointer to the packet which should be freed -+ * -+ * Frees i3c_mctp_packet previously allocated via slab allocation -+ */ -+void i3c_mctp_packet_free(void *packet) ++static u32 ast2600_i2c_functionality(struct i2c_adapter *adap) +{ -+ kmem_cache_free(packet_cache, packet); ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} -+EXPORT_SYMBOL_GPL(i3c_mctp_packet_free); + -+static void i3c_mctp_client_free(struct i3c_mctp_client *client) -+{ -+ ptr_ring_cleanup(&client->rx_queue, &i3c_mctp_packet_free); ++static const struct i2c_algorithm i2c_ast2600_algorithm = { ++ .xfer = ast2600_i2c_controller_xfer, ++ .functionality = ast2600_i2c_functionality, ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ .reg_target = ast2600_i2c_reg_target, ++ .unreg_target = ast2600_i2c_unreg_target, ++#endif ++}; + -+ kfree(client); -+} ++static const struct i2c_adapter_quirks ast2600_i2c_quirks = { ++ .flags = I2C_AQ_NO_ZERO_LEN_READ, ++}; + -+static struct i3c_mctp_client *i3c_mctp_client_alloc(struct i3c_mctp *priv) ++static int ast2600_i2c_probe(struct platform_device *pdev) +{ -+ struct i3c_mctp_client *client; ++ struct device *dev = &pdev->dev; ++ struct ast2600_i2c_bus *i2c_bus; ++ struct reset_control *rst; ++ const char *xfer_mode; ++ struct resource *res; ++ u32 global_ctrl; + int ret; + -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ goto out; -+ -+ client->priv = priv; -+ ret = ptr_ring_init(&client->rx_queue, RX_RING_COUNT, GFP_KERNEL); -+ if (ret) -+ return ERR_PTR(ret); -+ init_waitqueue_head(&client->wait_queue); -+out: -+ return client; -+} ++ if (!device_property_present(dev, "aspeed,global-regs")) ++ return -ENODEV; + -+static struct i3c_mctp_client *i3c_mctp_find_client(struct i3c_mctp *priv, -+ struct i3c_mctp_packet *packet) -+{ -+ u8 *msg_hdr = (u8 *)packet->data.payload; -+ u8 mctp_type = msg_hdr[MCTP_MSG_HDR_MSG_TYPE_OFFSET]; -+ u16 vendor = (msg_hdr[MCTP_MSG_HDR_VENDOR_OFFSET] << 8 -+ | msg_hdr[MCTP_MSG_HDR_VENDOR_OFFSET + 1]); -+ u8 intel_msg_op_code = msg_hdr[MCTP_MSG_HDR_OPCODE_OFFSET]; ++ i2c_bus = devm_kzalloc(dev, sizeof(*i2c_bus), GFP_KERNEL); ++ if (!i2c_bus) ++ return -ENOMEM; + -+ if (priv->peci_client && mctp_type == MCTP_MSG_TYPE_VDM_PCI && -+ vendor == MCTP_VDM_PCI_INTEL_VENDOR_ID && intel_msg_op_code == MCTP_VDM_PCI_INTEL_PECI) -+ return priv->peci_client; ++ i2c_bus->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(i2c_bus->reg_base)) ++ return PTR_ERR(i2c_bus->reg_base); + -+ return priv->default_client; -+} ++ rst = devm_reset_control_get_shared(dev, NULL); ++ if (IS_ERR(rst)) ++ return dev_err_probe(dev, PTR_ERR(rst), "Missing reset ctrl\n"); + -+static struct i3c_mctp_packet *i3c_mctp_read_packet(struct i3c_device *i3c) -+{ -+ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3c)); -+ struct i3c_mctp_packet *rx_packet; -+ struct i3c_priv_xfer xfers = { -+ .rnw = true, -+ }; -+ int ret; ++ reset_control_deassert(rst); + -+ rx_packet = i3c_mctp_packet_alloc(GFP_KERNEL); -+ if (!rx_packet) -+ return ERR_PTR(-ENOMEM); ++ i2c_bus->version = (enum i2c_version)device_get_match_data(dev); + -+ rx_packet->size = I3C_MCTP_PACKET_SIZE; -+ xfers.len = rx_packet->size; -+ xfers.data.in = &rx_packet->data; ++ i2c_bus->global_regs = ++ syscon_regmap_lookup_by_phandle(dev_of_node(dev), "aspeed,global-regs"); ++ if (IS_ERR(i2c_bus->global_regs)) ++ return PTR_ERR(i2c_bus->global_regs); + -+ /* Check against packet size + PEC byte to make sure that we always try to read max */ -+ if (priv->max_read_len != xfers.len + 1) { -+ dev_dbg(i3cdev_to_dev(i3c), "Length mismatch. MRL = %d, xfers.len = %d", -+ priv->max_read_len, xfers.len); -+ i3c_mctp_packet_free(rx_packet); -+ return ERR_PTR(-EINVAL); ++ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CTRL, &global_ctrl); ++ if ((global_ctrl & AST2600_GLOBAL_INIT) != AST2600_GLOBAL_INIT) { ++ regmap_write(i2c_bus->global_regs, AST2600_I2CG_CTRL, AST2600_GLOBAL_INIT); ++ if (i2c_bus->version == AST2600) ++ regmap_write(i2c_bus->global_regs, ++ AST2600_I2CG_CLK_DIV_CTRL, AST2600_I2CCG_DIV_CTRL); ++ else ++ regmap_write(i2c_bus->global_regs, ++ AST2600_I2CG_CLK_DIV_CTRL, AST2700_I2CCG_DIV_CTRL); + } -+ if (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && -+ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { -+ struct i3c_hdr_cmd cmds; -+ -+ cmds.mode = I3C_HDR_DDR; -+ cmds.code = 0x80; -+ cmds.ndatawords = DIV_ROUND_UP(rx_packet->size, 2); -+ cmds.data.in = &rx_packet->data; -+ ret = i3c_device_send_hdr_cmds(i3c, &cmds, 1); -+ if (!ret) -+ rx_packet->size = cmds.ndatawords; ++ ++ if (i2c_bus->version == AST2700) { ++ i2c_bus->ac_timing_config = ast2700_i2c_ac_timing_config; ++ i2c_bus->irq_err_to_errno = ast2700_i2c_irq_err_to_errno; ++ i2c_bus->irq_clear = ast2700_i2c_irq_clear; + } else { -+ ret = i3c_device_do_priv_xfers(i3c, &xfers, 1); -+ if (!ret) -+ rx_packet->size = xfers.len; -+ } -+ if (ret) { -+ i3c_mctp_packet_free(rx_packet); -+ return ERR_PTR(ret); ++ i2c_bus->ac_timing_config = ast2600_i2c_ac_timing_config; ++ i2c_bus->irq_err_to_errno = ast2600_i2c_irq_err_to_errno; ++ i2c_bus->irq_clear = ast2600_i2c_irq_clear; + } + -+ return rx_packet; -+} ++ /* Default BUFF mode, allow override */ ++ i2c_bus->mode = BUFF_MODE; + -+static void i3c_mctp_dispatch_packet(struct i3c_mctp *priv, struct i3c_mctp_packet *packet) -+{ -+ struct i3c_mctp_client *client = i3c_mctp_find_client(priv, packet); -+ int ret; ++ /* override the transfer mode */ ++ if (!device_property_read_string(dev, "aspeed,transfer-mode", &xfer_mode)) { ++ if (!strcmp(xfer_mode, "dma")) ++ i2c_bus->mode = DMA_MODE; ++ else if (!strcmp(xfer_mode, "byte")) ++ i2c_bus->mode = BYTE_MODE; ++ else ++ i2c_bus->mode = BUFF_MODE; ++ } + -+ ret = ptr_ring_produce(&client->rx_queue, packet); -+ if (ret) -+ i3c_mctp_packet_free(packet); -+ else -+ wake_up_all(&client->wait_queue); -+} ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ i2c_bus->target_operate = 0; ++ i2c_bus->target_attached = 0; ++ for (int i = 0; i < AST2600_I2C_TARGET_COUNT; i++) ++ i2c_bus->multi_target[i] = NULL; ++#endif ++ i2c_bus->dev = dev; ++ i2c_bus->multi_master = device_property_read_bool(dev, "multi-master"); + -+static void i3c_mctp_polling_work(struct work_struct *work) -+{ -+ struct i3c_mctp *priv = container_of(to_delayed_work(work), struct i3c_mctp, polling_work); -+ struct i3c_device *i3cdev = priv->i3c; -+ struct i3c_mctp_packet *rx_packet; -+ struct i3c_device_info info; -+ int ret; ++ if (i2c_bus->version == AST2700) { ++ /* select the transfer method*/ ++ u32 xfer_type = readl(i2c_bus->reg_base + I2CC_VERSION_CTRL); + -+ i3c_device_get_info(i3cdev, &info); -+ ret = i3c_device_getstatus_ccc(i3cdev, &info); -+ if (ret) -+ return; ++ /* AST2700 would not allow byte mode */ ++ if (i2c_bus->mode == BYTE_MODE) ++ i2c_bus->mode = DMA_MODE; + -+ if (CCC_DEVICE_STATUS_PENDING_INTR(info.status) != MCTP_INTERRUPT_NUMBER) -+ return; ++ if (i2c_bus->mode == DMA_MODE) { ++ /* ast2700 cfg enable dma */ ++ xfer_type |= FUNC_CFG_DMA_EN; ++ } else if (i2c_bus->mode == BUFF_MODE) { ++ i2c_bus->buf_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); ++ if (IS_ERR(i2c_bus->buf_base)) { ++ i2c_bus->mode = DMA_MODE; ++ } else { ++ i2c_bus->buf_size = resource_size(res) / 4; + -+ rx_packet = i3c_mctp_read_packet(i3cdev); -+ if (IS_ERR(rx_packet)) -+ goto out; ++ /* ast2700 cfg disable dma */ ++ xfer_type &= ~FUNC_CFG_DMA_EN; ++ } ++ } ++ writel(xfer_type, i2c_bus->reg_base + I2CC_VERSION_CTRL); ++ } else { ++ if (i2c_bus->mode == BUFF_MODE) { ++ i2c_bus->buf_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); ++ if (IS_ERR(i2c_bus->buf_base)) ++ i2c_bus->mode = BYTE_MODE; ++ else ++ i2c_bus->buf_size = resource_size(res) / 2; ++ } ++ } + -+ i3c_mctp_dispatch_packet(priv, rx_packet); -+out: -+ schedule_delayed_work(&priv->polling_work, msecs_to_jiffies(POLLING_TIMEOUT_MS)); -+} ++ switch (i2c_bus->mode) { ++ case DMA_MODE: ++ i2c_bus->setup_tx = ast2600_i2c_setup_dma_tx; ++ i2c_bus->setup_rx = ast2600_i2c_setup_dma_rx; ++ break; ++ case BUFF_MODE: ++ default: ++ if (i2c_bus->version == AST2700) { ++ i2c_bus->setup_tx = ast2700_i2c_setup_buff_tx; ++ i2c_bus->setup_rx = ast2700_i2c_setup_buff_rx; ++ } else { ++ i2c_bus->setup_tx = ast2600_i2c_setup_buff_tx; ++ i2c_bus->setup_rx = ast2600_i2c_setup_buff_rx; ++ } ++ break; ++ case BYTE_MODE: ++ i2c_bus->setup_tx = ast2600_i2c_setup_byte_tx; ++ i2c_bus->setup_rx = ast2600_i2c_setup_byte_rx; ++ break; ++ } + -+static ssize_t i3c_mctp_write(struct file *file, const char __user *buf, size_t count, -+ loff_t *f_pos) -+{ -+ struct i3c_mctp *priv = file->private_data; -+ struct i3c_device *i3c = priv->i3c; -+ struct i3c_priv_xfer xfers = { -+ .rnw = false, -+ .len = count, -+ }; -+ u8 *data; -+ int ret; ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ switch (i2c_bus->mode) { ++ case DMA_MODE: ++ if (i2c_bus->version == AST2700) ++ i2c_bus->target_packet_irq = ast2700_i2c_target_packet_dma_irq; ++ else ++ i2c_bus->target_packet_irq = ast2600_i2c_target_packet_dma_irq; ++ break; ++ case BUFF_MODE: ++ default: ++ if (i2c_bus->version == AST2700) ++ i2c_bus->target_packet_irq = ast2700_i2c_target_packet_buff_irq; ++ else ++ i2c_bus->target_packet_irq = ast2600_i2c_target_packet_buff_irq; ++ break; ++ case BYTE_MODE: ++ i2c_bus->target_byte_irq = ast2600_i2c_target_byte_irq; ++ break; ++ } ++#endif + + /* -+ * Check against packet size + PEC byte -+ * to not send more data than it was set in the probe ++ * i2c timeout counter: use base clk4 1Mhz, ++ * per unit: 1/(1000/1024) = 1024us ++ * lower than 1024 us will be set 1 ms. + */ -+ if (priv->max_write_len < xfers.len + 1) { -+ dev_dbg(i3cdev_to_dev(i3c), "Length mismatch. MWL = %d, xfers.len = %d", -+ priv->max_write_len, xfers.len); -+ return -EINVAL; ++ ret = device_property_read_u32(dev, "i2c-scl-clk-low-timeout-us", &i2c_bus->timeout); ++ if (!ret) { ++ i2c_bus->timeout = DIV_ROUND_UP(i2c_bus->timeout, 1024); + } + -+ data = memdup_user(buf, count); -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ if (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && -+ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { -+ struct i3c_hdr_cmd cmds; ++ init_completion(&i2c_bus->cmd_complete); + -+ cmds.mode = I3C_HDR_DDR; -+ cmds.code = 0; -+ cmds.ndatawords = DIV_ROUND_UP(count, 2); -+ cmds.data.out = data; -+ ret = i3c_device_send_hdr_cmds(i3c, &cmds, 1); -+ } else { -+ xfers.data.out = data; ++ i2c_bus->irq = platform_get_irq(pdev, 0); ++ if (i2c_bus->irq < 0) ++ return i2c_bus->irq; + -+ ret = i3c_device_do_priv_xfers(i3c, &xfers, 1); -+ } -+ kfree(data); -+ return ret ?: count; -+} ++ platform_set_drvdata(pdev, i2c_bus); + -+static ssize_t i3c_mctp_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) -+{ -+ struct i3c_mctp *priv = file->private_data; -+ struct i3c_mctp_client *client = priv->default_client; -+ struct i3c_mctp_packet *rx_packet; ++ i2c_bus->clk = devm_clk_get(i2c_bus->dev, NULL); ++ if (IS_ERR(i2c_bus->clk)) ++ return dev_err_probe(i2c_bus->dev, PTR_ERR(i2c_bus->clk), "Can't get clock\n"); + -+ if (count > sizeof(rx_packet->data)) -+ count = sizeof(rx_packet->data); ++ i2c_bus->apb_clk = clk_get_rate(i2c_bus->clk); + -+ rx_packet = ptr_ring_consume(&client->rx_queue); -+ if (!rx_packet) -+ return -EAGAIN; ++ i2c_parse_fw_timings(i2c_bus->dev, &i2c_bus->timing_info, true); + -+ if (count > rx_packet->size) -+ count = rx_packet->size; ++ /* Initialize the I2C adapter */ ++ i2c_bus->adap.owner = THIS_MODULE; ++ i2c_bus->adap.algo = &i2c_ast2600_algorithm; ++ i2c_bus->adap.quirks = &ast2600_i2c_quirks; ++ i2c_bus->adap.retries = 0; ++ i2c_bus->adap.dev.parent = i2c_bus->dev; ++ device_set_node(&i2c_bus->adap.dev, dev_fwnode(dev)); ++ i2c_bus->adap.algo_data = i2c_bus; ++ strscpy(i2c_bus->adap.name, pdev->name); ++ i2c_set_adapdata(&i2c_bus->adap, i2c_bus); ++ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + -+ if (copy_to_user(buf, &rx_packet->data, count)) -+ return -EFAULT; ++ ret = ast2600_i2c_init(i2c_bus); ++ if (ret < 0) ++ return dev_err_probe(dev, ret, "Unable to initial i2c %d\n", ret); + -+ i3c_mctp_packet_free(rx_packet); ++ ret = devm_request_irq(dev, i2c_bus->irq, ast2600_i2c_bus_irq, 0, ++ dev_name(dev), i2c_bus); ++ if (ret < 0) { ++ ret = dev_err_probe(dev, ret, "Unable to request irq %d\n", ++ i2c_bus->irq); ++ goto err; ++ } + -+ return count; -+} ++ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER, ++ i2c_bus->reg_base + AST2600_I2CM_IER); + -+static int i3c_mctp_open(struct inode *inode, struct file *file) -+{ -+ struct i3c_mctp *priv = container_of(inode->i_cdev, struct i3c_mctp, cdev); ++ ret = devm_i2c_add_adapter(dev, &i2c_bus->adap); ++ if (ret) ++ goto err; + -+ spin_lock(&priv->device_file_lock); -+ if (priv->device_open) { -+ spin_unlock(&priv->device_file_lock); -+ return -EBUSY; ++ i2c_bus->alert_enable = device_property_read_bool(dev, "smbus-alert"); ++ if (i2c_bus->alert_enable) { ++ i2c_bus->ara = i2c_new_smbus_alert_device(&i2c_bus->adap, &i2c_bus->alert_data); ++ if (!i2c_bus->ara) ++ dev_warn(dev, "Failed to register ARA client\n"); ++ else ++ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER | ++ AST2600_I2CM_SMBUS_ALERT, ++ i2c_bus->reg_base + AST2600_I2CM_IER); ++ } else { ++ i2c_bus->alert_enable = false; + } -+ priv->device_open++; -+ /* Discard all of the packet in the rx_queue */ -+ while (ptr_ring_consume(&priv->default_client->rx_queue)) -+ ; -+ spin_unlock(&priv->device_file_lock); + -+ file->private_data = priv; ++ dev_info(dev, "%s [%d]: adapter [%d KHz] mode [%d] version [%d]\n", ++ dev->of_node->name, i2c_bus->adap.nr, i2c_bus->timing_info.bus_freq_hz / 1000, ++ i2c_bus->mode, i2c_bus->version); + + return 0; ++ ++err: ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(0, i2c_bus->reg_base + AST2600_I2CM_IER); ++ return ret; +} + -+static int i3c_mctp_release(struct inode *inode, struct file *file) ++static void ast2600_i2c_remove(struct platform_device *pdev) +{ -+ struct i3c_mctp *priv = file->private_data; ++ struct ast2600_i2c_bus *i2c_bus = platform_get_drvdata(pdev); ++ ++ /* Disable everything. */ ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(0, i2c_bus->reg_base + AST2600_I2CM_IER); ++} + -+ spin_lock(&priv->device_file_lock); -+ priv->device_open--; -+ spin_unlock(&priv->device_file_lock); ++static const struct of_device_id ast2600_i2c_of_match[] = { ++ { .compatible = "aspeed,ast2600-i2cv2", .data = (const void *)AST2600, }, ++ { .compatible = "aspeed,ast2700-i2c", .data = (const void *)AST2700, }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, ast2600_i2c_of_match); + -+ file->private_data = NULL; ++static struct platform_driver ast2600_i2c_driver = { ++ .probe = ast2600_i2c_probe, ++ .remove = ast2600_i2c_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = ast2600_i2c_of_match, ++ }, ++}; ++module_platform_driver(ast2600_i2c_driver); + -+ return 0; ++MODULE_AUTHOR("Ryan Chen "); ++MODULE_DESCRIPTION("ASPEED AST2600 I2C Controller Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/i3c/master/ast2600-i3c-master.c b/drivers/i3c/master/ast2600-i3c-master.c +--- a/drivers/i3c/master/ast2600-i3c-master.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/i3c/master/ast2600-i3c-master.c 2026-09-09 15:51:44.672238767 +0000 +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + + #include "dw-i3c-master.h" + +@@ -33,18 +35,97 @@ + #define AST2600_I3CG_REG1_SA_EN BIT(15) + #define AST2600_I3CG_REG1_INST_ID_MASK GENMASK(19, 16) + #define AST2600_I3CG_REG1_INST_ID(x) (((x) << 16) & AST2600_I3CG_REG1_INST_ID_MASK) ++#define SCL_SW_MODE_OE BIT(20) ++#define SCL_OUT_SW_MODE_VAL BIT(21) ++#define SCL_IN_SW_MODE_VAL BIT(23) ++#define SDA_SW_MODE_OE BIT(24) ++#define SDA_OUT_SW_MODE_VAL BIT(25) ++#define SDA_IN_SW_MODE_VAL BIT(27) ++#define SCL_IN_SW_MODE_EN BIT(28) ++#define SDA_IN_SW_MODE_EN BIT(29) ++#define SCL_OUT_SW_MODE_EN BIT(30) ++#define SDA_OUT_SW_MODE_EN BIT(31) + + #define AST2600_DEFAULT_SDA_PULLUP_OHMS 2000 + ++#define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) ++#define DEV_ADDR_TABLE_DYNAMIC_ADDR GENMASK(23, 16) ++#define DEV_ADDR_TABLE_IBI_ADDR_MASK GENMASK(25, 24) ++#define IBI_ADDR_MASK_OFF 0b00 ++#define IBI_ADDR_MASK_LAST_3BITS 0b01 ++#define IBI_ADDR_MASK_LAST_4BITS 0b10 ++#define DEV_ADDR_TABLE_DA_PARITY BIT(23) ++#define DEV_ADDR_TABLE_MR_REJECT BIT(14) ++#define DEV_ADDR_TABLE_SIR_REJECT BIT(13) ++#define DEV_ADDR_TABLE_IBI_MDB BIT(12) + #define DEV_ADDR_TABLE_IBI_PEC BIT(11) ++#define DEV_ADDR_TABLE_STATIC_ADDR GENMASK(6, 0) ++ ++#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) ++ ++#define DEVICE_CTRL 0x0 ++#define DEV_CTRL_SLAVE_MDB GENMASK(23, 16) ++#define DEV_CTRL_HOT_JOIN_NACK BIT(8) ++ ++#define NUM_OF_SWDATS_IN_GROUP 8 ++#define ALL_DATS_IN_GROUP_ARE_FREE ((1 << NUM_OF_SWDATS_IN_GROUP) - 1) ++#define NUM_OF_SWDAT_GROUP 16 ++ ++#define ADDR_GRP_MASK GENMASK(6, 3) ++#define ADDR_GRP(x) (((x) & ADDR_GRP_MASK) >> 3) ++#define ADDR_HID_MASK GENMASK(2, 0) ++#define ADDR_HID(x) ((x) & ADDR_HID_MASK) ++ ++#define IBI_QUEUE_STATUS 0x18 ++#define IBI_QUEUE_STATUS_DATA_LEN(x) ((x) & GENMASK(7, 0)) ++ ++#define IBI_SIR_REQ_REJECT 0x30 ++#define INTR_STATUS_EN 0x40 ++#define INTR_SIGNAL_EN 0x44 ++#define INTR_IBI_THLD_STAT BIT(2) ++ ++#define QUEUE_STATUS_LEVEL 0x4c ++#define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24) ++ ++#define PRESENT_STATE 0x54 ++#define CM_TFR_STS GENMASK(13, 8) ++#define CM_TFR_STS_MASTER_SERV_IBI 0xe ++#define SDA_LINE_SIGNAL_LEVEL BIT(1) ++#define SCL_LINE_SIGNAL_LEVEL BIT(0) ++ ++struct ast2600_i3c_swdat_group { ++ u32 dat[NUM_OF_SWDATS_IN_GROUP]; ++ u32 free_pos; ++ int hw_index; ++ struct { ++ u32 set; ++ u32 clr; ++ } mask; ++}; + + struct ast2600_i3c { + struct dw_i3c_master dw; + struct regmap *global_regs; + unsigned int global_idx; + unsigned int sda_pullup; ++ ++ struct ast2600_i3c_swdat_group dat_group[NUM_OF_SWDAT_GROUP]; + }; + ++static u8 even_parity(u8 p) ++{ ++ p ^= p >> 4; ++ p &= 0xf; ++ ++ return (0x9669 >> p) & 1; +} + -+static __poll_t i3c_mctp_poll(struct file *file, struct poll_table_struct *pt) ++static inline struct dw_i3c_master * ++to_dw_i3c_master(struct i3c_master_controller *master) +{ -+ struct i3c_mctp *priv = file->private_data; -+ __poll_t ret = 0; ++ return container_of(master, struct dw_i3c_master, base); ++} + -+ poll_wait(file, &priv->default_client->wait_queue, pt); + static struct ast2600_i3c *to_ast2600_i3c(struct dw_i3c_master *dw) + { + return container_of(dw, struct ast2600_i3c, dw); +@@ -117,9 +198,559 @@ + } + } + ++static void ast2600_i3c_enter_sw_mode(struct dw_i3c_master *dw) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+ if (__ptr_ring_peek(&priv->default_client->rx_queue)) -+ ret |= EPOLLIN; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_VAL | SDA_IN_SW_MODE_VAL, ++ SCL_IN_SW_MODE_VAL | SDA_IN_SW_MODE_VAL); + -+ return ret; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN, ++ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN); +} + -+static const struct file_operations i3c_mctp_fops = { -+ .owner = THIS_MODULE, -+ .read = i3c_mctp_read, -+ .write = i3c_mctp_write, -+ .poll = i3c_mctp_poll, -+ .open = i3c_mctp_open, -+ .release = i3c_mctp_release, -+}; ++static void ast2600_i3c_exit_sw_mode(struct dw_i3c_master *dw) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+/** -+ * i3c_mctp_add_peci_client() - registers PECI client -+ * @i3c: I3C device to get the PECI client for -+ * -+ * Return: pointer to PECI client, -ENOMEM - in case of client alloc fault -+ */ -+struct i3c_mctp_client *i3c_mctp_add_peci_client(struct i3c_device *i3c) ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN, 0); ++} ++ ++static void ast2600_i3c_toggle_scl_in(struct dw_i3c_master *dw, int count) +{ -+ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3c)); -+ struct i3c_mctp_client *client; ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+ client = i3c_mctp_client_alloc(priv); -+ if (IS_ERR(client)) -+ return ERR_PTR(-ENOMEM); ++ for (; count; count--) { ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_VAL, 0); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_VAL, SCL_IN_SW_MODE_VAL); ++ } ++} + -+ priv->peci_client = client; ++static void ast2600_i3c_gen_internal_stop(struct dw_i3c_master *dw) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+ return priv->peci_client; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_VAL, 0); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_VAL, 0); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_VAL, SCL_IN_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_VAL, SDA_IN_SW_MODE_VAL); +} -+EXPORT_SYMBOL_GPL(i3c_mctp_add_peci_client); + -+/** -+ * i3c_mctp_remove_peci_client() - un-registers PECI client -+ * @client: i3c_mctp_client to be freed -+ */ -+void i3c_mctp_remove_peci_client(struct i3c_mctp_client *client) ++static int aspeed_i3c_bus_recovery(struct dw_i3c_master *dw) +{ -+ struct i3c_mctp *priv = client->priv; ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ int i, ret = -1; ++ ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_SW_MODE_OE, SCL_SW_MODE_OE); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_EN, SCL_OUT_SW_MODE_EN); ++ ++ for (i = 0; i < 19; i++) { ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, 0); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); ++ if (readl(dw->regs + PRESENT_STATE) & SDA_LINE_SIGNAL_LEVEL) { ++ ret = 0; ++ break; ++ } ++ } + -+ i3c_mctp_client_free(priv->peci_client); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_EN, 0); ++ if (ret) ++ dev_err(&dw->base.dev, "Failed to recover the bus\n"); + -+ priv->peci_client = NULL; ++ return ret; +} -+EXPORT_SYMBOL_GPL(i3c_mctp_remove_peci_client); + -+static struct i3c_mctp *i3c_mctp_alloc(struct i3c_device *i3c) ++static void ast2600_i3c_gen_target_reset_pattern(struct dw_i3c_master *dw) +{ -+ struct i3c_mctp *priv; -+ int id; -+ -+ priv = devm_kzalloc(i3cdev_to_dev(i3c), sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return ERR_PTR(-ENOMEM); ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ int i; + -+ id = ida_alloc(&i3c_mctp_ida, GFP_KERNEL); -+ if (id < 0) { -+ pr_err("i3c_mctp: no minor number available!\n"); -+ return ERR_PTR(id); ++ if (dw->base.bus.context == I3C_BUS_CONTEXT_JESD403) { ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_SW_MODE_OE, SCL_SW_MODE_OE); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_EN, SCL_OUT_SW_MODE_EN); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, 0); ++ mdelay(DIV_ROUND_UP(dw->timing.timed_reset_scl_low_ns, ++ 1000000)); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_EN, 0); ++ return; + } + -+ priv->id = id; -+ priv->i3c = i3c; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_VAL | SCL_OUT_SW_MODE_VAL, ++ SDA_OUT_SW_MODE_VAL | SCL_OUT_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_SW_MODE_OE | SCL_SW_MODE_OE, ++ SDA_SW_MODE_OE | SCL_SW_MODE_OE); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_EN | SCL_OUT_SW_MODE_EN, ++ SDA_OUT_SW_MODE_EN | SCL_OUT_SW_MODE_EN); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_VAL | SCL_IN_SW_MODE_VAL, ++ SDA_IN_SW_MODE_VAL | SCL_IN_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN, ++ SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, 0); ++ for (i = 0; i < 7; i++) { ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_VAL, 0); ++ regmap_write_bits(i3c->global_regs, ++ AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_VAL, SDA_OUT_SW_MODE_VAL); ++ } ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_OUT_SW_MODE_VAL, SCL_OUT_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_VAL, 0); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_VAL, SDA_OUT_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_OUT_SW_MODE_EN | SCL_OUT_SW_MODE_EN, 0); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN, 0); ++} + -+ spin_lock_init(&priv->device_file_lock); ++static void aspeed_i3c_drain_ibi_queue(struct dw_i3c_master *dw) ++{ ++ /* ++ * Clear the IBI queue to avoid any stale IBI data when ++ * re-enabling the controller. ++ */ ++ u32 ibi_status = readl(dw->regs + IBI_QUEUE_STATUS); ++ u8 length = IBI_QUEUE_STATUS_DATA_LEN(ibi_status); ++ int i, nwords = (length + 3) >> 2; + -+ return priv; ++ for (i = 0; i < nwords; i++) ++ readl(dw->regs + IBI_QUEUE_STATUS); +} + -+static void i3c_mctp_ibi_handler(struct i3c_device *dev, const struct i3c_ibi_payload *payload) ++static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) +{ -+ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(dev)); -+ struct i3c_mctp_packet *rx_packet; ++ u32 state; + -+ rx_packet = i3c_mctp_read_packet(dev); -+ if (IS_ERR(rx_packet)) -+ return; ++ /* ++ * Clear the IBI queue to enable the hardware to generate SCL and ++ * begin detecting the T-bit low to stop reading IBI data. ++ */ ++ aspeed_i3c_drain_ibi_queue(dw); ++ state = FIELD_GET(CM_TFR_STS, readl(dw->regs + PRESENT_STATE)); ++ if (state == CM_TFR_STS_MASTER_SERV_IBI) ++ return false; + -+ i3c_mctp_dispatch_packet(priv, rx_packet); ++ return true; +} + -+static int i3c_mctp_init(struct i3c_driver *drv) ++static void ast2600_i3c_gen_tbits_in(struct dw_i3c_master *dw) +{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ bool is_halted; ++ u32 nibi, i; + int ret; + -+ packet_cache = kmem_cache_create_usercopy("mctp-i3c-packet", -+ sizeof(struct i3c_mctp_packet), 0, 0, 0, -+ sizeof(struct i3c_mctp_packet), NULL); -+ if (IS_ERR(packet_cache)) { -+ ret = PTR_ERR(packet_cache); -+ goto out; -+ } -+ -+ /* Dynamically request unused major number */ -+ ret = alloc_chrdev_region(&i3c_mctp_devt, 0, I3C_MCTP_MINORS, "i3c-mctp"); -+ if (ret) -+ goto out; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_VAL, SDA_IN_SW_MODE_VAL); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_EN, SDA_IN_SW_MODE_EN); + -+ /* Create a class to populate sysfs entries*/ -+ i3c_mctp_class = class_create("i3c-mctp"); -+ if (IS_ERR(i3c_mctp_class)) { -+ ret = PTR_ERR(i3c_mctp_class); -+ goto out_unreg_chrdev; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_VAL, 0); ++ ret = readx_poll_timeout_atomic(ast2600_i3c_fsm_exit_serv_ibi, dw, ++ is_halted, is_halted, 0, 2000000); ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SDA_IN_SW_MODE_EN, 0); ++ if (ret) { ++ dev_err(&dw->base.dev, ++ "Failed to exit the I3C fsm from %lx(MASTER_SERV_IBI): %d", ++ FIELD_GET(CM_TFR_STS, readl(dw->regs + PRESENT_STATE)), ++ ret); ++ } else { ++ /* Clear the dummy data generated in this recovery process */ ++ nibi = readl(dw->regs + QUEUE_STATUS_LEVEL); ++ nibi = QUEUE_STATUS_IBI_STATUS_CNT(nibi); ++ for (i = 0; i < nibi; i++) ++ aspeed_i3c_drain_ibi_queue(dw); + } -+ -+ i3c_driver_register(drv); -+ -+ return 0; -+ -+out_unreg_chrdev: -+ unregister_chrdev_region(i3c_mctp_devt, I3C_MCTP_MINORS); -+out: -+ pr_err("i3c_mctp: driver initialisation failed\n"); -+ return ret; +} + -+static void i3c_mctp_free(struct i3c_driver *drv) ++static void ast2600_i3c_set_ibi_mdb(struct dw_i3c_master *dw, u8 mdb) +{ -+ i3c_driver_unregister(drv); -+ class_destroy(i3c_mctp_class); -+ unregister_chrdev_region(i3c_mctp_devt, I3C_MCTP_MINORS); -+ kmem_cache_destroy(packet_cache); ++ u32 reg; ++ ++ reg = readl(dw->regs + DEVICE_CTRL); ++ reg &= ~DEV_CTRL_SLAVE_MDB; ++ reg |= FIELD_PREP(DEV_CTRL_SLAVE_MDB, mdb); ++ writel(reg, dw->regs + DEVICE_CTRL); +} + -+static int i3c_mctp_enable_ibi(struct i3c_device *i3cdev) ++static int ast2600_i3c_get_free_hw_pos(struct dw_i3c_master *dw) +{ -+ struct i3c_ibi_setup ibireq = { -+ .handler = i3c_mctp_ibi_handler, -+ .max_payload_len = 2, -+ .num_slots = 10, -+ }; -+ int ret; -+ -+ ret = i3c_device_request_ibi(i3cdev, &ibireq); -+ if (ret) -+ return ret; -+ ret = i3c_device_enable_ibi(i3cdev); -+ if (ret) -+ i3c_device_free_ibi(i3cdev); ++ if (!(dw->free_pos & GENMASK(dw->maxdevs - 1, 0))) ++ return -ENOSPC; + -+ return ret; ++ return ffs(dw->free_pos) - 1; +} + -+static void i3c_mctp_disable_ibi(struct i3c_device *i3cdev) ++static void ast2600_i3c_init_swdat(struct dw_i3c_master *dw) +{ -+ i3c_device_disable_ibi(i3cdev); -+ i3c_device_free_ibi(i3cdev); -+} ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp; ++ int i, j; ++ u32 def_set, def_clr; + -+/** -+ * i3c_mctp_get_eid() - receive MCTP EID assigned to the device -+ * -+ * @client: client for the device to get the EID for -+ * @domain_id: requested domain ID -+ * @eid: pointer to store EID value -+ * -+ * Receive MCTP endpoint ID dynamically assigned by the MCTP Bus Owner -+ * Return: 0 in case of success, a negative error code otherwise. -+ */ -+int i3c_mctp_get_eid(struct i3c_mctp_client *client, u8 domain_id, u8 *eid) -+{ -+ /* TODO: Implement EID assignment basing on domain ID */ -+ *eid = 1; -+ return 0; -+} -+EXPORT_SYMBOL_GPL(i3c_mctp_get_eid); ++ def_clr = DEV_ADDR_TABLE_IBI_ADDR_MASK; ++ def_set = DEV_ADDR_TABLE_MR_REJECT | DEV_ADDR_TABLE_SIR_REJECT; + -+/** -+ * i3c_mctp_send_packet() - send mctp packet -+ * -+ * @tx_packet: the allocated packet that needs to be send via I3C -+ * @i3c: i3c device to send the packet to -+ * -+ * Return: 0 in case of success, a negative error code otherwise. -+ */ -+int i3c_mctp_send_packet(struct i3c_device *i3c, struct i3c_mctp_packet *tx_packet) -+{ -+ if (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && -+ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { -+ struct i3c_hdr_cmd cmds; ++ for (i = 0; i < NUM_OF_SWDAT_GROUP; i++) { ++ gp = &i3c->dat_group[i]; ++ gp->hw_index = -1; ++ gp->free_pos = ALL_DATS_IN_GROUP_ARE_FREE; ++ gp->mask.clr = def_clr; ++ gp->mask.set = def_set; + -+ cmds.mode = I3C_HDR_DDR; -+ cmds.code = 0; -+ cmds.ndatawords = DIV_ROUND_UP(tx_packet->size, 2); -+ cmds.data.out = &tx_packet->data; -+ return i3c_device_send_hdr_cmds(i3c, &cmds, 1); ++ for (j = 0; j < NUM_OF_SWDATS_IN_GROUP; j++) ++ gp->dat[j] = 0; + } -+ struct i3c_priv_xfer xfers; + -+ xfers.rnw = false; -+ xfers.len = tx_packet->size; -+ xfers.data.out = &tx_packet->data; -+ return i3c_device_do_priv_xfers(i3c, &xfers, 1); ++ for (i = 0; i < dw->maxdevs; i++) ++ writel(def_set, ++ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, i)); +} -+EXPORT_SYMBOL_GPL(i3c_mctp_send_packet); + -+/** -+ * i3c_mctp_receive_packet() - receive mctp packet -+ * -+ * @client: i3c_mctp_client to receive the packet from -+ * @timeout: timeout, in jiffies -+ * -+ * The function will sleep for up to @timeout if no packet is ready to read. -+ * -+ * Returns struct i3c_mctp_packet from or ERR_PTR in case of error or the -+ * timeout elapsed. -+ */ -+struct i3c_mctp_packet *i3c_mctp_receive_packet(struct i3c_mctp_client *client, -+ unsigned long timeout) ++static int ast2600_i3c_set_swdat(struct dw_i3c_master *dw, u8 addr, u32 val) +{ -+ struct i3c_mctp_packet *rx_packet; -+ int ret; ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; ++ int pos = ADDR_HID(addr); + -+ ret = wait_event_interruptible_timeout(client->wait_queue, -+ __ptr_ring_peek(&client->rx_queue), timeout); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ else if (ret == 0) -+ return ERR_PTR(-ETIME); ++ if (!(val & DEV_ADDR_TABLE_LEGACY_I2C_DEV)) { ++ /* Calculate DA parity for I3C devices */ ++ val &= ~DEV_ADDR_TABLE_DA_PARITY; ++ val |= FIELD_PREP(DEV_ADDR_TABLE_DA_PARITY, even_parity(addr)); ++ } ++ gp->dat[pos] = val; + -+ rx_packet = ptr_ring_consume(&client->rx_queue); -+ if (!rx_packet) -+ return ERR_PTR(-EAGAIN); ++ if (val) { ++ gp->free_pos &= ~BIT(pos); + -+ return rx_packet; -+} -+EXPORT_SYMBOL_GPL(i3c_mctp_receive_packet); ++ /* ++ * reserve the hw dat resource for the first member of the ++ * group. all the members in the group share the same hw dat. ++ */ ++ if (gp->hw_index == -1) { ++ gp->hw_index = ast2600_i3c_get_free_hw_pos(dw); ++ if (gp->hw_index < 0) ++ goto out; + -+static void i3c_mctp_i3c_event_cb(struct i3c_device *dev, enum i3c_event event) -+{ -+ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(dev)); ++ dw->free_pos &= ~BIT(gp->hw_index); ++ val &= ~gp->mask.clr; ++ val |= gp->mask.set; ++ writel(val, ++ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, ++ gp->hw_index)); ++ } ++ } else { ++ gp->free_pos |= BIT(pos); + -+ switch (event) { -+ case i3c_event_prepare_for_rescan: + /* -+ * Disable IBI and polling mode blindly. ++ * release the hw dat resource if all the members in the group ++ * are free. + */ -+ i3c_mctp_disable_ibi(dev); -+ cancel_delayed_work(&priv->polling_work); -+ break; -+ case i3c_event_rescan_done: -+ if (i3c_mctp_enable_ibi(dev)) { -+ INIT_DELAYED_WORK(&priv->polling_work, -+ i3c_mctp_polling_work); -+ schedule_delayed_work(&priv->polling_work, -+ msecs_to_jiffies(POLLING_TIMEOUT_MS)); ++ if (gp->free_pos == ALL_DATS_IN_GROUP_ARE_FREE) { ++ writel(gp->mask.set, ++ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, ++ gp->hw_index)); ++ dw->free_pos |= BIT(gp->hw_index); ++ gp->hw_index = -1; + } -+ break; -+ default: -+ break; + } ++out: ++ return gp->hw_index; +} + -+static int i3c_mctp_probe(struct i3c_device *i3cdev) ++static u32 ast2600_i3c_get_swdat(struct dw_i3c_master *dw, u8 addr) +{ -+ int ibi_payload_size = I3C_MCTP_IBI_PAYLOAD_SIZE; -+ struct device *dev = i3cdev_to_dev(i3cdev); -+ struct i3c_device_info info; -+ struct i3c_mctp *priv; -+ int ret; -+ -+ priv = i3c_mctp_alloc(i3cdev); -+ if (IS_ERR(priv)) -+ return PTR_ERR(priv); -+ -+ cdev_init(&priv->cdev, &i3c_mctp_fops); -+ -+ priv->cdev.owner = THIS_MODULE; -+ ret = cdev_add(&priv->cdev, MKDEV(MAJOR(i3c_mctp_devt), priv->id), 1); -+ if (ret) -+ goto error_cdev; -+ -+ /* register this i3c device with the driver core */ -+ priv->dev = device_create(i3c_mctp_class, dev, -+ MKDEV(MAJOR(i3c_mctp_devt), priv->id), -+ NULL, "i3c-mctp-%d", priv->id); -+ if (IS_ERR(priv->dev)) { -+ ret = PTR_ERR(priv->dev); -+ goto error; -+ } -+ -+ ret = i3c_device_control_pec(i3cdev, true); -+ if (ret) -+ dev_warn(priv->dev, "Hardware not support pec"); -+ -+ priv->default_client = i3c_mctp_client_alloc(priv); -+ if (IS_ERR(priv->default_client)) -+ goto error; -+ -+ dev_set_drvdata(i3cdev_to_dev(i3cdev), priv); -+ -+ priv->i3c_peci = platform_device_register_data(i3cdev_to_dev(i3cdev), "peci-i3c", priv->id, -+ NULL, 0); -+ if (IS_ERR(priv->i3c_peci)) -+ dev_warn(priv->dev, "failed to register peci-i3c device\n"); ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; + -+ i3c_device_register_event_cb(i3cdev, i3c_mctp_i3c_event_cb); -+ if (i3c_mctp_enable_ibi(i3cdev)) { -+ INIT_DELAYED_WORK(&priv->polling_work, i3c_mctp_polling_work); -+ schedule_delayed_work(&priv->polling_work, msecs_to_jiffies(POLLING_TIMEOUT_MS)); -+ ibi_payload_size = 0; -+ } ++ return gp->dat[ADDR_HID(addr)]; ++} + -+ i3c_device_get_info(i3cdev, &info); ++static int ast2600_i3c_flush_swdat(struct dw_i3c_master *dw, u8 addr) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; ++ u32 dat = gp->dat[ADDR_HID(addr)]; ++ int hw_index = gp->hw_index; + -+ ret = i3c_device_getmrl_ccc(i3cdev, &info); -+ if (ret || info.max_read_len != I3C_MCTP_MIN_TRANSFER_SIZE) -+ ret = i3c_device_setmrl_ccc(i3cdev, &info, I3C_MCTP_MIN_TRANSFER_SIZE, -+ ibi_payload_size); -+ if (ret && info.max_read_len != I3C_MCTP_MIN_TRANSFER_SIZE) { -+ dev_err(dev, "Failed to set MRL!, ret = %d\n", ret); -+ goto error_peci; -+ } -+ priv->max_read_len = info.max_read_len; ++ if (!dat || hw_index < 0) ++ return -1; + -+ ret = i3c_device_getmwl_ccc(i3cdev, &info); -+ if (ret || info.max_write_len != I3C_MCTP_MIN_TRANSFER_SIZE) -+ ret = i3c_device_setmwl_ccc(i3cdev, &info, I3C_MCTP_MIN_TRANSFER_SIZE); -+ if (ret && info.max_write_len != I3C_MCTP_MIN_TRANSFER_SIZE) { -+ dev_err(dev, "Failed to set MWL!, ret = %d\n", ret); -+ goto error_peci; -+ } -+ priv->max_write_len = info.max_write_len; ++ dat &= ~gp->mask.clr; ++ dat |= gp->mask.set; ++ writel(dat, dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, hw_index)); + + return 0; -+ -+error_peci: -+ platform_device_unregister(priv->i3c_peci); -+ i3c_device_disable_ibi(i3cdev); -+ i3c_device_free_ibi(i3cdev); -+error: -+ cdev_del(&priv->cdev); -+error_cdev: -+ put_device(dev); -+ return ret; +} + -+static void i3c_mctp_remove(struct i3c_device *i3cdev) ++static int ast2600_i3c_get_swdat_hw_pos(struct dw_i3c_master *dw, u8 addr) +{ -+ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); -+ -+ i3c_mctp_disable_ibi(i3cdev); -+ i3c_mctp_client_free(priv->default_client); -+ priv->default_client = NULL; -+ platform_device_unregister(priv->i3c_peci); ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; + -+ device_destroy(i3c_mctp_class, MKDEV(MAJOR(i3c_mctp_devt), priv->id)); -+ cdev_del(&priv->cdev); -+ ida_free(&i3c_mctp_ida, priv->id); ++ return gp->hw_index; +} + -+static const struct i3c_device_id i3c_mctp_ids[] = { -+ I3C_CLASS(0xCC, 0x0), -+ I3C_DEVICE(0x3f6, 0x8000, (void *)0), -+ I3C_DEVICE(0x3f6, 0x8001, (void *)0), -+ I3C_DEVICE(0x3f6, 0xA001, (void *)0), -+ I3C_DEVICE(0x3f6, 0xA003, (void *)0), -+ I3C_DEVICE(0x3f6, 0x0503, (void *)0), -+ { }, -+}; -+ -+static struct i3c_driver i3c_mctp_drv = { -+ .driver.name = "i3c-mctp", -+ .id_table = i3c_mctp_ids, -+ .probe = i3c_mctp_probe, -+ .remove = i3c_mctp_remove, -+}; -+ -+module_driver(i3c_mctp_drv, i3c_mctp_init, i3c_mctp_free); -+MODULE_AUTHOR("Oleksandr Shulzhenko "); -+MODULE_DESCRIPTION("I3C MCTP driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/i3c/mctp/i3c-target-mctp.c b/drivers/i3c/mctp/i3c-target-mctp.c ---- a/drivers/i3c/mctp/i3c-target-mctp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i3c/mctp/i3c-target-mctp.c 2025-12-23 10:16:19.325062821 +0000 -@@ -0,0 +1,485 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright (C) 2022 Intel Corporation.*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define I3C_CRC8_POLYNOMIAL 0x07 -+DECLARE_CRC8_TABLE(i3c_crc8_table); -+ -+#define I3C_TARGET_MCTP_MINORS 32 -+#define RX_RING_COUNT 16 -+ -+/* -+ * IBI Mandatory Data Byte -+ * https://www.mipi.org/mipi_i3c_mandatory_data_byte_values_public -+ * -+ * MCTP: -+ * bit[7:5] = 3'b101 -+ * bit[4:0] = 5'h0E -+ */ -+#define I3C_MCTP_MDB 0xae -+ -+static struct class *i3c_target_mctp_class; -+static dev_t i3c_target_mctp_devt; -+static DEFINE_IDA(i3c_target_mctp_ida); -+ -+struct mctp_client; ++static int ast2600_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev, ++ u8 old_dyn_addr) ++{ ++ struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct dw_i3c_master *master = to_dw_i3c_master(m); ++ u32 dat = FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_ADDR, dev->info.dyn_addr); + -+struct i3c_target_mctp { -+ struct i3c_device *i3cdev; -+ struct cdev cdev; -+ int id; -+ struct mctp_client *client; -+ spinlock_t client_lock; /* to protect client access */ -+ bool mdb_append_pec; -+}; ++ if (old_dyn_addr != dev->info.dyn_addr) ++ ast2600_i3c_set_swdat(master, old_dyn_addr, 0); + -+struct mctp_client { -+ struct kref ref; -+ struct i3c_target_mctp *priv; -+ struct ptr_ring rx_queue; -+ wait_queue_head_t wait_queue; -+}; ++ ast2600_i3c_set_swdat(master, dev->info.dyn_addr, dat); ++ data->index = ast2600_i3c_get_swdat_hw_pos(master, dev->info.dyn_addr); ++ master->devs[dev->info.dyn_addr].addr = dev->info.dyn_addr; + -+struct mctp_packet { -+ u8 *data; -+ u16 count; -+}; ++ return 0; ++} + -+static void *i3c_target_mctp_packet_alloc(u16 count) ++static int ast2600_i3c_attach_i3c_dev(struct i3c_dev_desc *dev) +{ -+ struct mctp_packet *packet; -+ u8 *data; -+ -+ packet = kzalloc(sizeof(*packet), GFP_ATOMIC); -+ if (!packet) -+ return NULL; ++ struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct dw_i3c_master *master = to_dw_i3c_master(m); ++ int pos; ++ u8 addr = dev->info.dyn_addr ?: dev->info.static_addr; + -+ data = kzalloc(count, GFP_ATOMIC); -+ if (!data) { -+ kfree(packet); -+ return NULL; -+ } ++ pos = ast2600_i3c_set_swdat(master, addr, ++ FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_ADDR, addr)); ++ if (pos < 0) ++ return pos; + -+ packet->data = data; -+ packet->count = count; ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; + -+ return packet; -+} ++ data->index = ast2600_i3c_get_swdat_hw_pos(master, addr); ++ master->devs[addr].addr = addr; ++ i3c_dev_set_master_data(dev, data); + -+static void i3c_target_mctp_packet_free(void *data) -+{ -+ struct mctp_packet *packet = data; ++ if (master->base.bus.context == I3C_BUS_CONTEXT_JESD403) { ++ dev->info.max_write_ds = 0; ++ dev->info.max_read_ds = 0; ++ } + -+ kfree(packet->data); -+ kfree(packet); ++ return 0; +} + -+static struct mctp_client *i3c_target_mctp_client_alloc(struct i3c_target_mctp *priv) ++static void ast2600_i3c_detach_i3c_dev(struct i3c_dev_desc *dev) +{ -+ struct mctp_client *client; ++ struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct dw_i3c_master *master = to_dw_i3c_master(m); ++ u8 addr = dev->info.dyn_addr ?: dev->info.static_addr; + -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ goto out; ++ ast2600_i3c_set_swdat(master, addr, 0); + -+ kref_init(&client->ref); -+ client->priv = priv; -+ ptr_ring_init(&client->rx_queue, RX_RING_COUNT, GFP_KERNEL); -+out: -+ return client; ++ i3c_dev_set_master_data(dev, NULL); ++ master->devs[addr].addr = 0; ++ kfree(data); +} + -+static void i3c_target_mctp_client_free(struct kref *ref) ++static int ast2600_i3c_attach_i2c_dev(struct i2c_dev_desc *dev) +{ -+ struct mctp_client *client = container_of(ref, typeof(*client), ref); ++ struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i2c_dev_get_master(dev); ++ struct dw_i3c_master *master = to_dw_i3c_master(m); ++ int pos; + -+ ptr_ring_cleanup(&client->rx_queue, &i3c_target_mctp_packet_free); ++ pos = ast2600_i3c_set_swdat(master, dev->addr, ++ DEV_ADDR_TABLE_LEGACY_I2C_DEV | ++ FIELD_PREP(DEV_ADDR_TABLE_STATIC_ADDR, dev->addr)); ++ if (pos < 0) ++ return pos; + -+ kfree(client); -+} ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; + -+static void i3c_target_mctp_client_get(struct mctp_client *client) -+{ -+ kref_get(&client->ref); -+} ++ data->index = ast2600_i3c_get_swdat_hw_pos(master, dev->addr); ++ master->devs[dev->addr].addr = dev->addr; ++ i2c_dev_set_master_data(dev, data); + -+static void i3c_target_mctp_client_put(struct mctp_client *client) -+{ -+ kref_put(&client->ref, &i3c_target_mctp_client_free); ++ return 0; +} + -+static void -+i3c_target_mctp_rx_packet_enqueue(struct i3c_device *i3cdev, const u8 *data, size_t count) ++static void ast2600_i3c_detach_i2c_dev(struct i2c_dev_desc *dev) +{ -+ struct i3c_target_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); -+ struct mctp_client *client; -+ struct mctp_packet *packet; -+ int ret; -+ -+ spin_lock(&priv->client_lock); -+ client = priv->client; -+ if (client) -+ i3c_target_mctp_client_get(client); -+ spin_unlock(&priv->client_lock); -+ -+ if (!client) -+ return; -+ -+ packet = i3c_target_mctp_packet_alloc(count); -+ if (!packet) -+ goto err; ++ struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i2c_dev_get_master(dev); ++ struct dw_i3c_master *master = to_dw_i3c_master(m); + -+ memcpy(packet->data, data, count); ++ ast2600_i3c_set_swdat(master, dev->addr, 0); + -+ ret = ptr_ring_produce(&client->rx_queue, packet); -+ if (ret) -+ i3c_target_mctp_packet_free(packet); -+ else -+ wake_up_all(&client->wait_queue); -+err: -+ i3c_target_mctp_client_put(client); ++ i2c_dev_set_master_data(dev, NULL); ++ master->devs[dev->addr].addr = 0; ++ kfree(data); +} + -+static struct mctp_client *i3c_target_mctp_create_client(struct i3c_target_mctp *priv) ++static void ast2600_i3c_set_sir_enabled(struct dw_i3c_master *dw, ++ struct i3c_dev_desc *dev, u8 idx, ++ bool enable) +{ -+ struct mctp_client *client; -+ int ret; -+ -+ /* Currently, we support just one client. */ -+ spin_lock_irq(&priv->client_lock); -+ ret = priv->client ? -EBUSY : 0; -+ spin_unlock_irq(&priv->client_lock); -+ -+ if (ret) -+ return ERR_PTR(ret); -+ -+ client = i3c_target_mctp_client_alloc(priv); -+ if (!client) -+ return ERR_PTR(-ENOMEM); ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = ++ &i3c->dat_group[ADDR_GRP(dev->info.dyn_addr)]; ++ unsigned long flags; ++ u32 reg; ++ bool global; + -+ init_waitqueue_head(&client->wait_queue); ++ spin_lock_irqsave(&dw->devs_lock, flags); ++ if (enable) { ++ gp->mask.clr |= DEV_ADDR_TABLE_SIR_REJECT | ++ DEV_ADDR_TABLE_IBI_ADDR_MASK; + -+ spin_lock_irq(&priv->client_lock); -+ priv->client = client; -+ spin_unlock_irq(&priv->client_lock); ++ gp->mask.set &= ~DEV_ADDR_TABLE_SIR_REJECT; ++ gp->mask.set |= FIELD_PREP(DEV_ADDR_TABLE_IBI_ADDR_MASK, ++ IBI_ADDR_MASK_LAST_3BITS); ++ /* ++ * The ast2600 i3c controller will lock up on receiving 4n+1-byte IBIs ++ * if the PEC is disabled. We have no way to restrict the length of ++ * IBIs sent to the controller, so we need to unconditionally enable ++ * PEC checking, which means we drop a byte of payload data ++ */ ++ gp->mask.set |= DEV_ADDR_TABLE_IBI_PEC; ++ if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) ++ gp->mask.set |= DEV_ADDR_TABLE_IBI_MDB; ++ } else { ++ reg = ast2600_i3c_get_swdat(dw, dev->info.dyn_addr); ++ reg |= DEV_ADDR_TABLE_SIR_REJECT; ++ ast2600_i3c_set_swdat(dw, dev->info.dyn_addr, reg); ++ } + -+ return client; -+} ++ reg = readl(dw->regs + IBI_SIR_REQ_REJECT); ++ if (enable) { ++ global = reg == 0xffffffff; ++ reg &= ~BIT(gp->hw_index); ++ } else { ++ int i; ++ bool hj_rejected = !!(readl(dw->regs + DEVICE_CTRL) & ++ DEV_CTRL_HOT_JOIN_NACK); ++ bool ibi_enable = false; + -+static void i3c_target_mctp_delete_client(struct mctp_client *client) -+{ -+ struct i3c_target_mctp *priv = client->priv; ++ for (i = 0; i < NUM_OF_SWDATS_IN_GROUP; i++) { ++ if (!(gp->dat[i] & DEV_ADDR_TABLE_SIR_REJECT)) { ++ ibi_enable = true; ++ break; ++ } ++ } + -+ spin_lock_irq(&priv->client_lock); -+ priv->client = NULL; -+ spin_unlock_irq(&priv->client_lock); ++ if (!ibi_enable) { ++ reg |= BIT(gp->hw_index); ++ global = (reg == 0xffffffff) && hj_rejected; + -+ i3c_target_mctp_client_put(client); -+} ++ gp->mask.set = DEV_ADDR_TABLE_SIR_REJECT; ++ } ++ } ++ writel(reg, dw->regs + IBI_SIR_REQ_REJECT); + -+static int i3c_target_mctp_open(struct inode *inode, struct file *file) -+{ -+ struct i3c_target_mctp *priv = container_of(inode->i_cdev, struct i3c_target_mctp, cdev); -+ struct mctp_client *client; ++ if (global) { ++ reg = readl(dw->regs + INTR_STATUS_EN); ++ reg &= ~INTR_IBI_THLD_STAT; ++ if (enable) ++ reg |= INTR_IBI_THLD_STAT; ++ writel(reg, dw->regs + INTR_STATUS_EN); + -+ client = i3c_target_mctp_create_client(priv); -+ if (IS_ERR(client)) -+ return PTR_ERR(client); ++ reg = readl(dw->regs + INTR_SIGNAL_EN); ++ reg &= ~INTR_IBI_THLD_STAT; ++ if (enable) ++ reg |= INTR_IBI_THLD_STAT; ++ writel(reg, dw->regs + INTR_SIGNAL_EN); ++ } + -+ file->private_data = client; ++ ast2600_i3c_flush_swdat(dw, dev->info.dyn_addr); + -+ return 0; ++ spin_unlock_irqrestore(&dw->devs_lock, flags); +} + -+static int i3c_target_mctp_release(struct inode *inode, struct file *file) ++static void ast2600_i3c_set_ibi_dev(struct dw_i3c_master *dw, ++ struct i3c_dev_desc *dev) +{ -+ struct mctp_client *client = file->private_data; -+ -+ i3c_target_mctp_delete_client(client); -+ -+ return 0; ++ dw->devs[dev->info.dyn_addr].ibi_dev = dev; +} + -+static ssize_t i3c_target_mctp_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) ++static void ast2600_i3c_unset_ibi_dev(struct dw_i3c_master *dw, ++ struct i3c_dev_desc *dev) +{ -+ struct mctp_client *client = file->private_data; -+ struct mctp_packet *rx_packet; -+ -+ rx_packet = ptr_ring_consume_irq(&client->rx_queue); -+ if (!rx_packet) -+ return -EAGAIN; -+ -+ if (count < rx_packet->count) { -+ count = -EINVAL; -+ goto err_free; -+ } -+ if (count > rx_packet->count) -+ count = rx_packet->count; -+ -+ if (copy_to_user(buf, rx_packet->data, count)) -+ count = -EFAULT; -+err_free: -+ i3c_target_mctp_packet_free(rx_packet); -+ -+ return count; ++ dw->devs[dev->info.dyn_addr].ibi_dev = NULL; +} + -+static u8 *pec_append(u8 addr_rnw, u8 *buf, u8 len) ++static struct i3c_dev_desc *ast2600_i3c_get_ibi_dev(struct dw_i3c_master *dw, ++ u8 addr) +{ -+ u8 pec_v; ++ return dw->devs[addr].ibi_dev; ++} + -+ pec_v = crc8(i3c_crc8_table, &addr_rnw, 1, 0); -+ pec_v = crc8(i3c_crc8_table, buf, len, pec_v); -+ buf[len] = pec_v; + static const struct dw_i3c_platform_ops ast2600_i3c_ops = { + .init = ast2600_i3c_init, + .set_dat_ibi = ast2600_i3c_set_dat_ibi, ++ .enter_sw_mode = ast2600_i3c_enter_sw_mode, ++ .exit_sw_mode = ast2600_i3c_exit_sw_mode, ++ .toggle_scl_in = ast2600_i3c_toggle_scl_in, ++ .gen_internal_stop = ast2600_i3c_gen_internal_stop, ++ .gen_target_reset_pattern = ast2600_i3c_gen_target_reset_pattern, ++ .gen_tbits_in = ast2600_i3c_gen_tbits_in, ++ .bus_recovery = aspeed_i3c_bus_recovery, ++ .set_ibi_mdb = ast2600_i3c_set_ibi_mdb, ++ .reattach_i3c_dev = ast2600_i3c_reattach_i3c_dev, ++ .attach_i3c_dev = ast2600_i3c_attach_i3c_dev, ++ .detach_i3c_dev = ast2600_i3c_detach_i3c_dev, ++ .attach_i2c_dev = ast2600_i3c_attach_i2c_dev, ++ .detach_i2c_dev = ast2600_i3c_detach_i2c_dev, ++ .get_addr_pos = ast2600_i3c_get_swdat_hw_pos, ++ .flush_dat = ast2600_i3c_flush_swdat, ++ .set_sir_enabled = ast2600_i3c_set_sir_enabled, ++ .set_ibi_dev = ast2600_i3c_set_ibi_dev, ++ .unset_ibi_dev = ast2600_i3c_unset_ibi_dev, ++ .get_ibi_dev = ast2600_i3c_get_ibi_dev, + }; + + static int ast2600_i3c_probe(struct platform_device *pdev) +@@ -156,6 +787,10 @@ + i3c->sda_pullup); + + i3c->dw.platform_ops = &ast2600_i3c_ops; ++ i3c->dw.base.pec_supported = true; + -+ return buf; -+} ++ ast2600_i3c_init_swdat(&i3c->dw); + -+static ssize_t i3c_target_mctp_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct mctp_client *client = file->private_data; -+ struct i3c_target_mctp *priv = client->priv; -+ struct i3c_priv_xfer xfers[2] = {}; -+ struct i3c_device_info info; -+ u8 *tx_data; -+ u8 *ibi_data; -+ int ret; -+ bool ibi_enabled = i3c_device_is_ibi_enabled(priv->i3cdev); + return dw_i3c_common_probe(&i3c->dw, pdev); + } + +diff --git a/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h b/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h +--- a/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/i3c/master/mipi-i3c-hci/vendor_aspeed.h 2026-09-09 15:51:44.665238872 +0000 +@@ -0,0 +1,453 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++#ifndef VENDOR_ASPEED_H ++#define VENDOR_ASPEED_H + -+ if (!ibi_enabled) { -+ dev_warn(i3cdev_to_dev(priv->i3cdev), "IBI not enabled\n"); -+ return count; -+ } -+ if (priv->mdb_append_pec) -+ ibi_data = kzalloc(2, GFP_KERNEL); -+ else -+ ibi_data = kzalloc(1, GFP_KERNEL); -+ if (!ibi_data) -+ return -ENOMEM; -+ ibi_data[0] = I3C_MCTP_MDB; ++/* Aspeed in-house register */ ++#include "linux/bitfield.h" ++#define ast_inhouse_read(r) readl(hci->INHOUSE_regs + (r)) ++#define ast_inhouse_write(r, v) writel(v, hci->INHOUSE_regs + (r)) + -+ tx_data = kzalloc(count, GFP_KERNEL); -+ if (!tx_data) { -+ ret = -ENOMEM; -+ goto free_ibi; -+ } ++#define ASPEED_I3C_CTRL 0x0 ++#define ASPEED_I3C_CTRL_STOP_QUEUE_PT BIT(31) //Stop the queue read pointer. ++#define ASPEED_I3C_CTRL_CLOCK_STALL_EN BIT(14) ++#define ASPEED_I3C_CTRL_INIT BIT(4) ++#define ASPEED_I3C_CTRL_INIT_MODE GENMASK(1, 0) ++#define INIT_MST_MODE 0 ++#define INIT_SEC_MST_MODE 1 ++#define INIT_SLV_MODE 2 + -+ if (copy_from_user(tx_data, buf, count)) { -+ ret = -EFAULT; -+ goto out_packet; -+ } ++#define ASPEED_I3C_STS 0x4 ++#define ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS_VALID BIT(23) ++#define ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS GENMASK(22, 16) ++#define ASPEED_I3C_STS_MODE_PURE_SLV BIT(8) ++#define ASPEED_I3C_STS_MODE_SECONDARY_SLV_TO_MST BIT(7) ++#define ASPEED_I3C_STS_MODE_SECONDARY_MST_TO_SLV BIT(6) ++#define ASPEED_I3C_STS_MODE_SECONDARY_SLV BIT(5) ++#define ASPEED_I3C_STS_MODE_SECONDARY_MST BIT(4) ++#define ASPEED_I3C_STS_MODE_PRIMARY_SLV_TO_MST BIT(3) ++#define ASPEED_I3C_STS_MODE_PRIMARY_MST_TO_SLV BIT(2) ++#define ASPEED_I3C_STS_MODE_PRIMARY_SLV BIT(1) ++#define ASPEED_I3C_STS_MODE_PRIMARY_MST BIT(0) + -+ i3c_device_get_info(priv->i3cdev, &info); -+ if (priv->mdb_append_pec) { -+ pec_append(info.dyn_addr << 1 | 0x1, ibi_data, 1); -+ xfers[0].len = 2; -+ } else { -+ xfers[0].len = 1; -+ } -+ xfers[0].data.out = ibi_data; ++#define ASPEED_I3C_MST_MRL 0x8 ++#define ASPEED_I3C_IBI_TERMINATE_EN BIT(16) ++#define ASPEED_I3C_IBI_TERMINATE_LEN GENMASK(15, 0) + -+ xfers[1].data.out = tx_data; -+ xfers[1].len = count; ++#define ASPEED_I3C_DAA_INDEX0 0x10 ++#define ASPEED_I3C_DAA_INDEX1 0x14 ++#define ASPEED_I3C_DAA_INDEX2 0x18 ++#define ASPEED_I3C_DAA_INDEX3 0x1C + -+ ret = i3c_device_pending_read_notify(priv->i3cdev, &xfers[1], -+ &xfers[0]); -+ if (ret) -+ goto out_packet; -+ ret = count; ++#define ASPEED_I3C_AUTOCMD_0 0x20 ++#define ASPEED_I3C_AUTOCMD_1 0x24 ++#define ASPEED_I3C_AUTOCMD_2 0x28 ++#define ASPEED_I3C_AUTOCMD_3 0x2C ++#define ASPEED_I3C_AUTOCMD_4 0x30 ++#define ASPEED_I3C_AUTOCMD_5 0x34 ++#define ASPEED_I3C_AUTOCMD_6 0x38 ++#define ASPEED_I3C_AUTOCMD_7 0x3C + -+out_packet: -+ kfree(tx_data); -+free_ibi: -+ kfree(ibi_data); -+ return ret; -+} ++#define ASPEED_I3C_AUTOCMD_SEL_0_7 0x40 ++#define ASPEED_I3C_AUTOCMD_SEL_8_15 0x44 ++#define ASPEED_I3C_AUTOCMD_SEL_16_23 0x48 ++#define ASPEED_I3C_AUTOCMD_SEL_24_31 0x4C ++#define ASPEED_I3C_AUTOCMD_SEL_32_39 0x50 ++#define ASPEED_I3C_AUTOCMD_SEL_40_47 0x54 ++#define ASPEED_I3C_AUTOCMD_SEL_48_55 0x58 ++#define ASPEED_I3C_AUTOCMD_SEL_56_63 0x5C ++#define ASPEED_I3C_AUTOCMD_SEL_64_71 0x60 ++#define ASPEED_I3C_AUTOCMD_SEL_72_79 0x64 ++#define ASPEED_I3C_AUTOCMD_SEL_80_87 0x68 ++#define ASPEED_I3C_AUTOCMD_SEL_88_95 0x6C ++#define ASPEED_I3C_AUTOCMD_SEL_96_103 0x70 ++#define ASPEED_I3C_AUTOCMD_SEL_104_111 0x74 ++#define ASPEED_I3C_AUTOCMD_SEL_112_119 0x78 ++#define ASPEED_I3C_AUTOCMD_SEL_120_127 0x7C + -+static __poll_t i3c_target_mctp_poll(struct file *file, struct poll_table_struct *pt) -+{ -+ struct mctp_client *client = file->private_data; -+ __poll_t ret = 0; ++#define ASPEED_I3C_WDMA_CTRL 0x80 ++#define ASPEED_I3C_WDMA_DBG_LO 0x84 ++#define ASPEED_I3C_WDMA_DBG_HI 0x88 ++#define ASPEED_I3C_RDMA_CTRL 0x90 ++#define ASPEED_I3C_RDMA_DBG_LO 0x94 ++#define ASPEED_I3C_RDMA_DBG_HI 0x98 ++#define I3C_DMA_DBG_LO_ABORT BIT(0) ++#define I3C_DMA_DBG_LO_BUSY BIT(1) ++#define I3C_DMA_DBG_LO_DONE BIT(2) ++#define I3C_DMA_DBG_LO_START BIT(3) ++#define I3C_DMA_DBG_LO_READY BIT(4) ++#define I3C_DMA_DBG_LO_VALID BIT(5) ++#define I3C_DMA_DBG_LO_EN BIT(10) ++ ++#define ASPEED_I3C_RING_STATUS 0x9C ++#define I3C_RING_IDLE 0 ++#define I3C_RING_GET_TRANSFER 1 ++#define I3C_RING_GET_TX_DATA 2 ++#define I3C_RING_CMD_PROCESS 3 ++#define I3C_RING_WRITE_RX_DATA 4 ++#define I3C_RING_WRITE_RESPONSE 5 ++#define I3C_RING_UPDATE_CR_PTR 6 ++#define I3C_RING_WRITE_IBI_STS 7 ++#define I3C_RING_WRITE_IBI_DAT 8 ++#define I3C_RING_UPDATE_IBI_PTR 9 ++#define I3C_RING_ABORT 10 ++#define I3C_RING_SLV_WRITE_DATA 11 ++#define I3C_RING_SLV_WRITE_RESPONSE 12 ++#define I3C_RING_SLV_UPDATE_PT 13 + -+ poll_wait(file, &client->wait_queue, pt); ++#define ASPEED_I3C_SLV_CHAR_CTRL 0xA0 ++#define ASPEED_I3C_SLV_CHAR_CTRL_DCR GENMASK(23, 16) ++#define ASPEED_I3C_SLV_CHAR_CTRL_BCR GENMASK(15, 8) ++#define SLV_BCR_DEVICE_ROLE GENMASK(7, 6) ++#define ASPEED_I3C_SLV_CHAR_CTRL_STATIC_ADDR_EN BIT(7) ++#define ASPEED_I3C_SLV_CHAR_CTRL_STATIC_ADDR GENMASK(6, 0) ++#define SLV_PID_HI(x) (((x) >> 32) & GENMASK(15, 0)) ++#define SLV_PID_LO(x) ((x) & GENMASK(31, 0)) ++#define ASPEED_I3C_SLV_PID_LO 0xA4 ++#define ASPEED_I3C_SLV_PID_HI 0xA8 ++#define ASPEED_I3C_SLV_FSM 0xAC ++#define ASPEED_I3C_SLV_CAP_CTRL 0xB0 ++#define ASPEED_I3C_SLV_CAP_CTRL_PEC_EN BIT(31) ++#define ASPEED_I3C_SLV_CAP_CTRL_HAIT_IF_IBI_ERR BIT(30) ++#define ASPEED_I3C_SLV_CAP_CTRL_ACCEPT_CR BIT(16) ++#define ASPEED_I3C_SLV_CAP_CTRL_HJ_REQ BIT(10) ++#define ASPEED_I3C_SLV_CAP_CTRL_MR_REQ BIT(9) ++#define ASPEED_I3C_SLV_CAP_CTRL_IBI_REQ BIT(8) ++#define ASPEED_I3C_SLV_CAP_CTRL_HJ_WAIT BIT(6) ++#define ASPEED_I3C_SLV_CAP_CTRL_MR_WAIT BIT(5) ++#define ASPEED_I3C_SLV_CAP_CTRL_IBI_WAIT BIT(4) ++#define ASPEED_I3C_SLV_CAP_CTRL_NOTSUP_DEF_BYTE BIT(1) ++#define ASPEED_I3C_SLV_CAP_CTRL_I2C_DEV BIT(0) ++/* CCC related registers */ ++#define ASPEED_I3C_SLV_STS1 0xB4 ++#define ASPEED_I3C_SLV_STS1_IBI_PAYLOAD_SIZE GENMASK(31, 24) ++#define ASPEED_I3C_SLV_STS1_RSTACT GENMASK(22, 16) ++/* the parameters for the HDR-DDR Data Transfer Early Termination procedure*/ ++#define ASPEED_I3C_SLV_STS1_ETP_ACK_CAP BIT(15) ++#define ASPEED_I3C_SLV_STS1_ETP_W_REQ BIT(14) ++#define ASPEED_I3C_SLV_STS1_ETP_CRC GENMASK(13, 12) ++#define ASPEED_I3C_SLV_STS1_ENDXFER_CONFIRM BIT(11) ++#define ASPEED_I3C_SLV_STS1_ENTER_TEST_MDOE BIT(8) ++#define ASPEED_I3C_SLV_STS1_HJ_EN BIT(6) ++#define ASPEED_I3C_SLV_STS1_CR_EN BIT(5) ++#define ASPEED_I3C_SLV_STS1_IBI_EN BIT(4) ++#define ASPEED_I3C_SLV_STS1_HJ_DONE BIT(2) ++#define ASPEED_I3C_SLV_STS1_CR_DONE BIT(1) ++#define ASPEED_I3C_SLV_STS1_IBI_DONE BIT(0) ++#define ASPEED_I3C_SLV_STS2 0xB8 ++#define ASPEED_I3C_SLV_STS2_MWL GENMASK(31, 16) ++#define ASPEED_I3C_SLV_STS2_MRL GENMASK(15, 0) ++#define ASPEED_I3C_SLV_STS3_GROUP_ADDR 0xBC ++#define ASPEED_I3C_SLV_STS3_GROUP3_VALID BIT(31) ++#define ASPEED_I3C_SLV_STS3_GROUP3_ADDR GENMASK(30, 24) ++#define ASPEED_I3C_SLV_STS3_GROUP2_VALID BIT(23) ++#define ASPEED_I3C_SLV_STS3_GROUP2_ADDR GENMASK(22, 16) ++#define ASPEED_I3C_SLV_STS3_GROUP1_VALID BIT(15) ++#define ASPEED_I3C_SLV_STS3_GROUP1_ADDR GENMASK(14, 8) ++#define ASPEED_I3C_SLV_STS3_GROUP0_VALID BIT(7) ++#define ASPEED_I3C_SLV_STS3_GROUP0_ADDR GENMASK(6, 0) ++#define ASPEED_I3C_SLV_STS4_RSTACT_TIME 0xC0 ++#define ASPEED_I3C_SLV_STS4_DBG_NET GENMASK(23, 16) ++#define ASPEED_I3C_SLV_STS4_WHOLE_CHIP GENMASK(15, 8) ++#define ASPEED_I3C_SLV_STS4_I3C GENMASK(7, 0) ++#define ASPEED_I3C_SLV_STS5_GETMXDS_RW 0xC4 ++#define ASPEED_I3C_SLV_STS5_MAXWR GENMASK(15, 8) ++#define ASPEED_I3C_SLV_STS5_MAXRD GENMASK(7, 0) ++#define ASPEED_I3C_SLV_STS6_GETMXDS 0xC8 ++#define ASPEED_I3C_SLV_STS6_FORMAT BIT(24) ++#define ASPEED_I3C_SLV_STS6_MAXRD_TURN_H GENMASK(23, 16) ++#define ASPEED_I3C_SLV_STS6_MAXRD_TURN_M GENMASK(15, 8) ++#define ASPEED_I3C_SLV_STS6_MAXRD_TURN_L GENMASK(7, 0) ++#define ASPEED_I3C_SLV_STS7_GETSTATUS 0xCC ++#define ASPEED_I3C_SLV_STS7_PRECR GENMASK(31, 16) ++#define ASPEED_I3C_SLV_STS7_TGT GENMASK(15, 0) ++#define ASPEED_I3C_SLV_STS8_GETCAPS_TGT 0xD0 ++#define ASPEED_I3C_SLV_STS9_GETCAPS_VT_CR 0xD4 ++#define ASPEED_I3C_SLV_STS7_VT GENMASK(31, 16) ++#define ASPEED_I3C_SLV_STS7_CR GENMASK(15, 0) + -+ if (__ptr_ring_peek(&client->rx_queue)) -+ ret |= EPOLLIN; ++#define ASPEED_I3C_QUEUE_PTR0 0xD8 ++#define QUEUE_PTR0_TX_R(q) FIELD_GET(GENMASK(24, 20), q) ++#define QUEUE_PTR0_TX_W(q) FIELD_GET(GENMASK(16, 12), q) ++#define QUEUE_PTR0_IBI_R(q) FIELD_GET(GENMASK(11, 10), q) ++#define QUEUE_PTR0_IBI_W(q) FIELD_GET(GENMASK(9, 8), q) ++#define QUEUE_PTR0_RESP_R(q) FIELD_GET(GENMASK(7, 6), q) ++#define QUEUE_PTR0_RESP_W(q) FIELD_GET(GENMASK(5, 4), q) ++#define QUEUE_PTR0_CMD_R(q) FIELD_GET(GENMASK(3, 2), q) ++#define QUEUE_PTR0_CMD_W(q) FIELD_GET(GENMASK(1, 0), q) + -+ /* -+ * TODO: Add support for "write" readiness. -+ * DW-I3C has a hardware queue that has finite number of entries. -+ * If we try to issue more writes that space in this queue allows for, -+ * we're in trouble. This should be handled by error from write() and -+ * poll() blocking for write events. -+ */ -+ return ret; -+} ++#define ASPEED_I3C_QUEUE_PTR1 0xDC ++#define QUEUE_PTR1_IBI_DATA_R(q) FIELD_GET(GENMASK(28, 24), q) ++#define QUEUE_PTR1_IBI_DATA_W(q) FIELD_GET(GENMASK(20, 16), q) ++#define QUEUE_PTR1_RX_R(q) FIELD_GET(GENMASK(12, 8), q) ++#define QUEUE_PTR1_RX_W(q) FIELD_GET(GENMASK(4, 0), q) + -+static const struct file_operations i3c_target_mctp_fops = { -+ .owner = THIS_MODULE, -+ .open = i3c_target_mctp_open, -+ .release = i3c_target_mctp_release, -+ .read = i3c_target_mctp_read, -+ .write = i3c_target_mctp_write, -+ .poll = i3c_target_mctp_poll, -+}; ++#define ASPEED_I3C_INTR_STATUS 0xE0 ++#define ASPEED_I3C_INTR_STATUS_ENABLE 0xE4 ++#define ASPEED_I3C_INTR_SIGNAL_ENABLE 0xE8 ++#define ASPEED_I3C_INTR_FORCE 0xEC ++#define ASPEED_I3C_INTR_I2C_SDA_STUCK_LOW BIT(14) ++#define ASPEED_I3C_INTR_I3C_SDA_STUCK_HIGH BIT(13) ++#define ASPEED_I3C_INTR_I3C_SDA_STUCK_LOW BIT(12) ++#define ASPEED_I3C_INTR_MST_INTERNAL_DONE BIT(10) ++#define ASPEED_I3C_INTR_MST_DDR_READ_DONE BIT(9) ++#define ASPEED_I3C_INTR_MST_DDR_WRITE_DONE BIT(8) ++#define ASPEED_I3C_INTR_MST_IBI_DONE BIT(7) ++#define ASPEED_I3C_INTR_MST_READ_DONE BIT(6) ++#define ASPEED_I3C_INTR_MST_WRITE_DONE BIT(5) ++#define ASPEED_I3C_INTR_MST_DAA_DONE BIT(4) ++#define ASPEED_I3C_INTR_SLV_SCL_STUCK BIT(1) ++#define ASPEED_I3C_INTR_TGRST BIT(0) + -+static struct i3c_target_read_setup i3c_target_mctp_rx_packet_setup = { -+ .handler = i3c_target_mctp_rx_packet_enqueue, -+}; ++#define ASPEED_I3C_INTR_SUM_STATUS 0xF0 ++#define ASPEED_INTR_SUM_INHOUSE BIT(3) ++#define ASPEED_INTR_SUM_RHS BIT(2) ++#define ASPEED_INTR_SUM_PIO BIT(1) ++#define ASPEED_INTR_SUM_CAP BIT(0) + -+static ssize_t mdb_append_pec_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ struct i3c_device *i3cdev = dev_get_drvdata(dev); -+ struct i3c_target_mctp *priv = i3cdev_get_drvdata(i3cdev); -+ ssize_t ret; ++#define ASPEED_I3C_INTR_RENEW 0xF4 + -+ ret = sysfs_emit(buf, "%d\n", priv->mdb_append_pec); ++/* Aspeed Phy register */ ++#define ast_phy_read(r) readl(hci->PHY_regs + (r)) ++#define ast_phy_write(r, v) writel(v, hci->PHY_regs + (r)) + -+ return ret; -+} ++#define PHY_SW_FORCE_CTRL 0x4 ++#define PHY_SW_FORCE_CTRL_SCL_IN_EN BIT(31) ++#define PHY_SW_FORCE_CTRL_SCL_OUT_EN BIT(30) ++#define PHY_SW_FORCE_CTRL_SCL_OE_EN BIT(29) ++#define PHY_SW_FORCE_CTRL_SCL_PU_EN BIT(28) ++#define PHY_SW_FORCE_CTRL_SDA_IN_EN BIT(27) ++#define PHY_SW_FORCE_CTRL_SDA_OUT_EN BIT(26) ++#define PHY_SW_FORCE_CTRL_SDA_OE_EN BIT(25) ++#define PHY_SW_FORCE_CTRL_SDA_PU_EN BIT(24) ++#define PHY_SW_FORCE_CTRL_SCL_IN_VAL BIT(13) ++#define PHY_SW_FORCE_CTRL_SCL_OUT_VAL BIT(12) ++#define PHY_SW_FORCE_CTRL_SCL_OE_VAL BIT(11) ++#define PHY_SW_FORCE_CTRL_SCL_PU_VAL GENMASK(10, 8) ++#define PHY_SW_FORCE_CTRL_SDA_IN_VAL BIT(5) ++#define PHY_SW_FORCE_CTRL_SDA_OUT_VAL BIT(4) ++#define PHY_SW_FORCE_CTRL_SDA_OE_VAL BIT(3) ++#define PHY_SW_FORCE_CTRL_SDA_PU_VAL GENMASK(2, 0) + -+static ssize_t mdb_append_pec_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct i3c_device *i3cdev = dev_get_drvdata(dev); -+ struct i3c_target_mctp *priv = i3cdev_get_drvdata(i3cdev); -+ bool res; -+ int ret; ++/* I2C FM: 400K */ ++#define PHY_I2C_FM_CTRL0 0x8 ++#define PHY_I2C_FM_CTRL0_CAS GENMASK(25, 16) ++#define PHY_I2C_FM_CTRL0_SU_STO GENMASK(9, 0) ++#define PHY_I2C_FM_CTRL1 0xC ++#define PHY_I2C_FM_CTRL1_SCL_H GENMASK(25, 16) ++#define PHY_I2C_FM_CTRL1_SCL_L GENMASK(9, 0) ++#define PHY_I2C_FM_CTRL2 0x10 ++#define PHY_I2C_FM_CTRL2_ACK_H GENMASK(25, 16) ++#define PHY_I2C_FM_CTRL2_ACK_L GENMASK(9, 0) ++#define PHY_I2C_FM_CTRL3 0x14 ++#define PHY_I2C_FM_CTRL3_HD_DAT GENMASK(25, 16) ++#define PHY_I2C_FM_CTRL3_AHD_DAT GENMASK(9, 0) + -+ ret = kstrtobool(buf, &res); -+ if (ret) -+ return ret; ++#define PHY_I2C_FM_DEFAULT_CAS_NS 1130 ++#define PHY_I2C_FM_DEFAULT_SU_STO_NS 1370 ++#define PHY_I2C_FM_DEFAULT_SCL_H_NS 1130 ++#define PHY_I2C_FM_DEFAULT_SCL_L_NS 1370 ++#define PHY_I2C_FM_DEFAULT_HD_DAT 10 ++#define PHY_I2C_FM_DEFAULT_AHD_DAT 10 + -+ priv->mdb_append_pec = res; ++/* I2C FMP: 1M */ ++#define PHY_I2C_FMP_CTRL0 0x18 ++#define PHY_I2C_FMP_CTRL0_CAS GENMASK(25, 16) ++#define PHY_I2C_FMP_CTRL0_SU_STO GENMASK(9, 0) ++#define PHY_I2C_FMP_CTRL1 0x1C ++#define PHY_I2C_FMP_CTRL1_SCL_H GENMASK(25, 16) ++#define PHY_I2C_FMP_CTRL1_SCL_L GENMASK(9, 0) ++#define PHY_I2C_FMP_CTRL2 0x20 ++#define PHY_I2C_FMP_CTRL2_ACK_H GENMASK(25, 16) ++#define PHY_I2C_FMP_CTRL2_ACK_L GENMASK(9, 0) ++#define PHY_I2C_FMP_CTRL3 0x24 ++#define PHY_I2C_FMP_CTRL3_HD_DAT GENMASK(25, 16) ++#define PHY_I2C_FMP_CTRL3_AHD_DAT GENMASK(9, 0) + -+ return count; -+} ++#define PHY_I2C_FMP_DEFAULT_CAS_NS 380 ++#define PHY_I2C_FMP_DEFAULT_SU_STO_NS 620 ++#define PHY_I2C_FMP_DEFAULT_SCL_H_NS 380 ++#define PHY_I2C_FMP_DEFAULT_SCL_L_NS 620 ++#define PHY_I2C_FMP_DEFAULT_HD_DAT 10 ++#define PHY_I2C_FMP_DEFAULT_AHD_DAT 10 + -+static DEVICE_ATTR_RW(mdb_append_pec); ++/* I3C OD */ ++#define PHY_I3C_OD_CTRL0 0x28 ++#define PHY_I3C_OD_CTRL0_CAS GENMASK(25, 16) ++#define PHY_I3C_OD_CTRL0_CBP GENMASK(9, 0) ++#define PHY_I3C_OD_CTRL1 0x2C ++#define PHY_I3C_OD_CTRL1_SCL_H GENMASK(25, 16) ++#define PHY_I3C_OD_CTRL1_SCL_L GENMASK(9, 0) ++#define PHY_I3C_OD_CTRL2 0x30 ++#define PHY_I3C_OD_CTRL2_ACK_H GENMASK(25, 16) ++#define PHY_I3C_OD_CTRL2_ACK_L GENMASK(9, 0) ++#define PHY_I3C_OD_CTRL3 0x34 ++#define PHY_I3C_OD_CTRL3_HD_DAT GENMASK(25, 16) ++#define PHY_I3C_OD_CTRL3_AHD_DAT GENMASK(9, 0) + -+static int i3c_target_mctp_probe(struct i3c_device *i3cdev) -+{ -+ struct device *parent = i3cdev_to_dev(i3cdev); -+ struct i3c_target_mctp *priv; -+ struct device *dev; -+ int ret; ++/* ++ * MIPI I3C minimum timing for the Open-Drain start/stop, expressed in tenths ++ * of a nanosecond to keep the fractional spec values (tCAS >= 38.4ns, ++ * tCBP >= 19.2ns) in integer arithmetic. ++ */ ++#define PHY_I3C_OD_MIN_CAS_NS_X10 384 ++#define PHY_I3C_OD_MIN_CBP_NS_X10 192 ++#define PHY_I3C_OD_DEFAULT_SCL_H_NS 380 ++#define PHY_I3C_OD_DEFAULT_SCL_L_NS 620 ++#define PHY_I3C_OD_DEFAULT_HD_DAT 10 ++#define PHY_I3C_OD_DEFAULT_AHD_DAT 10 + -+ priv = devm_kzalloc(parent, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++/* I3C PP SDR0 */ ++#define PHY_I3C_SDR0_CTRL0 0x38 ++#define PHY_I3C_SDR0_CTRL0_SCL_H GENMASK(25, 16) ++#define PHY_I3C_SDR0_CTRL0_SCL_L GENMASK(9, 0) ++#define PHY_I3C_SDR0_CTRL1 0x3C ++#define PHY_I3C_SDR0_CTRL1_TBIT_H GENMASK(25, 16) ++#define PHY_I3C_SDR0_CTRL1_TBIT_L GENMASK(9, 0) ++#define PHY_I3C_SDR0_CTRL2 0x40 ++#define PHY_I3C_SDR0_CTRL2_HD_PP GENMASK(25, 16) ++#define PHY_I3C_SDR0_CTRL2_TBIT_HD_PP GENMASK(9, 0) + -+ ret = ida_alloc(&i3c_target_mctp_ida, GFP_KERNEL); -+ if (ret < 0) -+ return ret; -+ priv->id = ret; ++/* 1MHz */ ++#define PHY_I3C_SDR0_DEFAULT_SCL_H_NS 380 ++#define PHY_I3C_SDR0_DEFAULT_SCL_L_NS 620 ++#define PHY_I3C_SDR0_DEFAULT_TBIT_H_NS 380 ++#define PHY_I3C_SDR0_DEFAULT_TBIT_L_NS 620 ++#define PHY_I3C_SDR0_DEFAULT_HD_PP_NS 10 ++#define PHY_I3C_SDR0_DEFAULT_TBIT_HD_PP_NS 10 + -+ priv->i3cdev = i3cdev; -+ spin_lock_init(&priv->client_lock); ++#define PHY_I3C_CTRL0_OFFSET 0x0 ++#define PHY_I3C_CTRL1_OFFSET 0x4 ++#define PHY_I3C_CTRL2_OFFSET 0x8 ++/* I3C PP SDR1 */ ++#define PHY_I3C_SDR1_CTRL0 0x44 ++#define PHY_I3C_SDR1_CTRL0_SCL_H GENMASK(25, 16) ++#define PHY_I3C_SDR1_CTRL0_SCL_L GENMASK(9, 0) ++#define PHY_I3C_SDR1_CTRL1 0x48 ++#define PHY_I3C_SDR1_CTRL1_TBIT_H GENMASK(25, 16) ++#define PHY_I3C_SDR1_CTRL1_TBIT_L GENMASK(9, 0) ++#define PHY_I3C_SDR1_CTRL2 0x4C ++#define PHY_I3C_SDR1_CTRL2_HD_PP GENMASK(25, 16) ++#define PHY_I3C_SDR1_CTRL2_TBIT_HD_PP GENMASK(9, 0) ++/* I3C PP SDR2 */ ++#define PHY_I3C_SDR2_CTRL0 0x50 ++#define PHY_I3C_SDR2_CTRL0_SCL_H GENMASK(25, 16) ++#define PHY_I3C_SDR2_CTRL0_SCL_L GENMASK(9, 0) ++#define PHY_I3C_SDR2_CTRL1 0x54 ++#define PHY_I3C_SDR2_CTRL1_TBIT_H GENMASK(25, 16) ++#define PHY_I3C_SDR2_CTRL1_TBIT_L GENMASK(9, 0) ++#define PHY_I3C_SDR2_CTRL2 0x58 ++#define PHY_I3C_SDR2_CTRL2_HD_PP GENMASK(25, 16) ++#define PHY_I3C_SDR2_CTRL2_TBIT_HD_PP GENMASK(9, 0) ++/* I3C PP SDR3 */ ++#define PHY_I3C_SDR3_CTRL0 0x5C ++#define PHY_I3C_SDR3_CTRL0_SCL_H GENMASK(25, 16) ++#define PHY_I3C_SDR3_CTRL0_SCL_L GENMASK(9, 0) ++#define PHY_I3C_SDR3_CTRL1 0x60 ++#define PHY_I3C_SDR3_CTRL1_TBIT_H GENMASK(25, 16) ++#define PHY_I3C_SDR3_CTRL1_TBIT_L GENMASK(9, 0) ++#define PHY_I3C_SDR3_CTRL2 0x64 ++#define PHY_I3C_SDR3_CTRL2_HD_PP GENMASK(25, 16) ++#define PHY_I3C_SDR3_CTRL2_TBIT_HD_PP GENMASK(9, 0) ++/* I3C PP SDR4 */ ++#define PHY_I3C_SDR4_CTRL0 0x68 ++#define PHY_I3C_SDR4_CTRL0_SCL_H GENMASK(25, 16) ++#define PHY_I3C_SDR4_CTRL0_SCL_L GENMASK(9, 0) ++#define PHY_I3C_SDR4_CTRL1 0x6C ++#define PHY_I3C_SDR4_CTRL1_TBIT_H GENMASK(25, 16) ++#define PHY_I3C_SDR4_CTRL1_TBIT_L GENMASK(9, 0) ++#define PHY_I3C_SDR4_CTRL2 0x70 ++#define PHY_I3C_SDR4_CTRL2_HD_PP GENMASK(25, 16) ++#define PHY_I3C_SDR4_CTRL2_TBIT_HD_PP GENMASK(9, 0) ++/* I3C PP DDR */ ++#define PHY_I3C_DDR_CTRL0 0x74 ++#define PHY_I3C_DDR_CTRL0_SCL_H GENMASK(25, 16) ++#define PHY_I3C_DDR_CTRL0_SCL_L GENMASK(9, 0) ++#define PHY_I3C_DDR_CTRL1 0x78 ++#define PHY_I3C_DDR_CTRL1_TBIT_H GENMASK(25, 16) ++#define PHY_I3C_DDR_CTRL1_TBIT_L GENMASK(9, 0) ++#define PHY_I3C_DDR_CTRL2 0x7C ++#define PHY_I3C_DDR_CTRL2_HD_PP GENMASK(25, 16) ++#define PHY_I3C_DDR_CTRL2_TBIT_HD_PP GENMASK(9, 0) + -+ cdev_init(&priv->cdev, &i3c_target_mctp_fops); -+ priv->cdev.owner = THIS_MODULE; ++/* 1MHz */ ++#define PHY_I3C_DDR_DEFAULT_SCL_H_NS 380 ++#define PHY_I3C_DDR_DEFAULT_SCL_L_NS 620 ++#define PHY_I3C_DDR_DEFAULT_TBIT_H_NS 380 ++#define PHY_I3C_DDR_DEFAULT_TBIT_L_NS 620 ++#define PHY_I3C_DDR_DEFAULT_HD_PP_NS 10 ++#define PHY_I3C_DDR_DEFAULT_TBIT_HD_PP_NS 10 + -+ ret = cdev_add(&priv->cdev, -+ MKDEV(MAJOR(i3c_target_mctp_devt), priv->id), 1); -+ if (ret) { -+ ida_free(&i3c_target_mctp_ida, priv->id); -+ return ret; -+ } ++#define PHY_I3C_SR_P_PREPARE_CTRL 0x80 ++#define PHY_I3C_SR_P_PREPARE_CTRL_HD GENMASK(25, 16) ++#define PHY_I3C_SR_P_PREPARE_CTRL_SCL_L GENMASK(9, 0) ++#define PHY_I3C_SR_P_DEFAULT_HD_NS 16 ++#define PHY_I3C_SR_P_DEFAULT_SCL_L_NS 40 + -+ dev = device_create(i3c_target_mctp_class, parent, -+ MKDEV(MAJOR(i3c_target_mctp_devt), priv->id), i3cdev, -+ "i3c-mctp-target-%d", priv->id); -+ if (IS_ERR(dev)) { -+ ret = PTR_ERR(dev); -+ goto err; -+ } ++#define PHY_PULLUP_EN 0x98 ++#define PHY_PULLUP_EN_SCL GENMASK(14, 12) ++#define PHY_PULLUP_EN_SDA GENMASK(10, 8) ++#define PHY_PULLUP_EN_DDR_SCL GENMASK(6, 4) ++#define PHY_PULLUP_EN_DDR_SDA GENMASK(2, 0) + -+ /* -+ * By default, the PEC is appended to the MDB as a hardware workaround for the AST2600 I3C -+ * controller as primary controller. -+ */ -+ priv->mdb_append_pec = 1; ++#define PHY_I3C_OD_CTRL4 0xD8 ++// SDA drive high (push-pull) time After tCBP ++#define PHY_I3C_OD_CTRL4_DAP GENMASK(26, 16) ++#define PHY_I3C_OD_DEFAULT_DAP_NS 12 + -+ ret = device_create_file(dev, &dev_attr_mdb_append_pec); -+ if (unlikely(ret)) { -+ dev_err(dev, "Failed creating device attrs\n"); -+ ret = -EINVAL; -+ goto err; -+ } ++static inline unsigned int aspeed_get_avail_tx_entries(struct i3c_hci *hci) ++{ ++ unsigned int queue_ptr, entries; + -+ i3cdev_set_drvdata(i3cdev, priv); ++ queue_ptr = ast_inhouse_read(ASPEED_I3C_QUEUE_PTR0); ++ if (QUEUE_PTR0_TX_W(queue_ptr) >= QUEUE_PTR0_TX_R(queue_ptr)) ++ entries = 0x20 - (QUEUE_PTR0_TX_W(queue_ptr) - ++ QUEUE_PTR0_TX_R(queue_ptr)); ++ else ++ entries = QUEUE_PTR0_TX_R(queue_ptr) - QUEUE_PTR0_TX_W(queue_ptr); + -+ i3c_target_read_register(i3cdev, &i3c_target_mctp_rx_packet_setup); ++ return entries; ++} + -+ crc8_populate_msb(i3c_crc8_table, I3C_CRC8_POLYNOMIAL); ++static inline unsigned int aspeed_get_received_rx_entries(struct i3c_hci *hci) ++{ ++ unsigned int queue_ptr, entries; + -+ return 0; -+err: -+ cdev_del(&priv->cdev); -+ ida_free(&i3c_target_mctp_ida, priv->id); ++ queue_ptr = ast_inhouse_read(ASPEED_I3C_QUEUE_PTR1); ++ if (QUEUE_PTR1_RX_W(queue_ptr) >= QUEUE_PTR1_RX_R(queue_ptr)) ++ entries = QUEUE_PTR1_RX_W(queue_ptr) - QUEUE_PTR1_RX_R(queue_ptr); ++ else ++ entries = 0x20 - (QUEUE_PTR1_RX_R(queue_ptr) - ++ QUEUE_PTR1_RX_W(queue_ptr)); + -+ return ret; ++ return entries; +} + -+static void i3c_target_mctp_remove(struct i3c_device *i3cdev) ++static inline unsigned int aspeed_get_i3c_revision_id(struct i3c_hci *hci) +{ -+ struct i3c_target_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); -+ -+ device_destroy(i3c_target_mctp_class, i3c_target_mctp_devt); -+ cdev_del(&priv->cdev); -+ ida_free(&i3c_target_mctp_ida, priv->id); ++ return FIELD_GET(GENMASK(23, 16), hci->vendor_product_id); +} + -+static const struct i3c_device_id i3c_target_mctp_ids[] = { -+ I3C_CLASS(0xcc, 0x0), -+ { }, -+}; -+ -+static struct i3c_driver i3c_target_mctp_drv = { -+ .driver.name = "i3c-target-mctp", -+ .id_table = i3c_target_mctp_ids, -+ .probe = i3c_target_mctp_probe, -+ .remove = i3c_target_mctp_remove, -+ .target = true, -+}; -+ -+static int i3c_target_mctp_init(struct i3c_driver *drv) ++static inline void aspeed_i3c_ccc_handler(struct i3c_hci *hci, u8 ccc) +{ -+ int ret; -+ -+ ret = alloc_chrdev_region(&i3c_target_mctp_devt, 0, -+ I3C_TARGET_MCTP_MINORS, "i3c-target-mctp"); -+ if (ret) -+ return ret; ++ u32 reg; ++ u8 dynamic_addr; + -+ i3c_target_mctp_class = class_create("i3c-target-mctp"); -+ if (IS_ERR(i3c_target_mctp_class)) { -+ unregister_chrdev_region(i3c_target_mctp_devt, I3C_TARGET_MCTP_MINORS); -+ return PTR_ERR(i3c_target_mctp_class); ++ switch (ccc) { ++ case I3C_CCC_RSTDAA(true): ++ case I3C_CCC_RSTDAA(false): ++ hci->master.this->info.dyn_addr = 0; ++ break; ++ case I3C_CCC_ENTDAA: ++ case I3C_CCC_SETDASA: ++ case I3C_CCC_SETNEWDA: ++ case I3C_CCC_SETAASA: ++ reg = ast_inhouse_read(ASPEED_I3C_STS); ++ if (reg & ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS_VALID) { ++ dynamic_addr = FIELD_GET(ASPEED_I3C_STS_SLV_DYNAMIC_ADDRESS, reg); ++ hci->master.this->info.dyn_addr = dynamic_addr; ++ } ++ break; + } -+ -+ return i3c_driver_register(drv); -+} -+ -+static void i3c_target_mctp_fini(struct i3c_driver *drv) -+{ -+ i3c_driver_unregister(drv); -+ class_destroy(i3c_target_mctp_class); -+ unregister_chrdev_region(i3c_target_mctp_devt, I3C_TARGET_MCTP_MINORS); +} + -+module_driver(i3c_target_mctp_drv, i3c_target_mctp_init, i3c_target_mctp_fini); -+MODULE_AUTHOR("Iwona Winiarska "); -+MODULE_DESCRIPTION("I3C Target MCTP driver"); -+MODULE_LICENSE("GPL"); ++#endif diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c ---- a/drivers/iio/adc/aspeed_adc.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/iio/adc/aspeed_adc.c 2025-12-23 10:16:20.950035586 +0000 +--- a/drivers/iio/adc/aspeed_adc.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/iio/adc/aspeed_adc.c 2026-09-09 15:51:44.513241169 +0000 @@ -72,6 +72,8 @@ #define ASPEED_ADC_BAT_SENSING_ENABLE BIT(13) #define ASPEED_ADC_CTRL_CHANNEL GENMASK(31, 16) @@ -39430,15 +39669,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c static void aspeed_adc_reset_assert(void *data) { struct reset_control *rst = data; -@@ -415,6 +572,7 @@ - } - adc_engine_control_reg_val = - readl(data->base + ASPEED_REG_ENGINE_CONTROL); -+ adc_engine_control_reg_val &= ~ASPEED_ADC_REF_VOLTAGE; - - ret = devm_regulator_get_enable_read_voltage(data->dev, "vref"); - if (ret < 0 && ret != -ENODEV) -@@ -474,6 +632,7 @@ +@@ -475,6 +632,7 @@ u32 adc_engine_control_reg_val; unsigned long scaler_flags = 0; char clk_name[32], clk_parent_name[32]; @@ -39446,7 +39677,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); if (!indio_dev) -@@ -488,12 +647,44 @@ +@@ -489,12 +647,44 @@ if (IS_ERR(data->base)) return PTR_ERR(data->base); @@ -39492,7 +39723,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c data->fixed_div_clk = clk_hw_register_fixed_factor( &pdev->dev, clk_name, clk_parent_name, 0, 1, 2); if (IS_ERR(data->fixed_div_clk)) -@@ -508,7 +699,7 @@ +@@ -509,7 +699,7 @@ if (data->model_data->need_prescaler) { snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler", @@ -39501,7 +39732,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c data->clk_prescaler = devm_clk_hw_register_divider( &pdev->dev, clk_name, clk_parent_name, 0, data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0, -@@ -524,7 +715,7 @@ +@@ -525,7 +715,7 @@ * setting to adjust the prescaler as well. */ snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler", @@ -39510,7 +39741,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c data->clk_scaler = devm_clk_hw_register_divider( &pdev->dev, clk_name, clk_parent_name, scaler_flags, data->base + ASPEED_REG_CLOCK_CONTROL, 0, -@@ -612,13 +803,25 @@ +@@ -613,13 +803,25 @@ aspeed_adc_compensation(indio_dev); /* Start all channels in normal mode. */ @@ -39541,7 +39772,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c indio_dev->info = &aspeed_adc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = data->battery_sensing ? -@@ -645,6 +848,16 @@ +@@ -646,6 +848,16 @@ .field = GENMASK(7, 4), }; @@ -39558,7 +39789,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c static const struct aspeed_adc_model_data ast2400_model_data = { .model_name = "ast2400-adc", .vref_fixed_mv = 2500, -@@ -653,6 +866,7 @@ +@@ -654,6 +866,7 @@ .need_prescaler = true, .scaler_bit_width = 10, .num_channels = 16, @@ -39566,7 +39797,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c }; static const struct aspeed_adc_model_data ast2500_model_data = { -@@ -665,6 +879,7 @@ +@@ -666,6 +879,7 @@ .scaler_bit_width = 10, .num_channels = 16, .trim_locate = &ast2500_adc_trim, @@ -39574,7 +39805,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c }; static const struct aspeed_adc_model_data ast2600_adc0_model_data = { -@@ -676,6 +891,7 @@ +@@ -677,6 +891,7 @@ .scaler_bit_width = 16, .num_channels = 8, .trim_locate = &ast2600_adc0_trim, @@ -39582,7 +39813,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c }; static const struct aspeed_adc_model_data ast2600_adc1_model_data = { -@@ -687,6 +903,29 @@ +@@ -688,6 +903,29 @@ .scaler_bit_width = 16, .num_channels = 8, .trim_locate = &ast2600_adc1_trim, @@ -39612,7 +39843,7 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c }; static const struct of_device_id aspeed_adc_matches[] = { -@@ -694,6 +933,8 @@ +@@ -695,6 +933,8 @@ { .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data }, { .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data }, { .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data }, @@ -39621,22 +39852,9 @@ diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c { } }; MODULE_DEVICE_TABLE(of, aspeed_adc_matches); -diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile ---- a/drivers/irqchip/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/irqchip/Makefile 2025-12-23 10:16:13.379162479 +0000 -@@ -83,8 +83,8 @@ - obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o - obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o - obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o --obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o -+obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o irq-aspeed-intc.o irq-aspeed-e2m-ic.o - obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o - obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o - obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o - obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o diff --git a/drivers/irqchip/irq-aspeed-e2m-ic.c b/drivers/irqchip/irq-aspeed-e2m-ic.c --- a/drivers/irqchip/irq-aspeed-e2m-ic.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/irqchip/irq-aspeed-e2m-ic.c 2025-12-23 10:16:21.166031966 +0000 ++++ b/drivers/irqchip/irq-aspeed-e2m-ic.c 2026-09-09 15:51:44.753237543 +0000 @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* @@ -39818,8 +40036,8 @@ diff --git a/drivers/irqchip/irq-aspeed-e2m-ic.c b/drivers/irqchip/irq-aspeed-e2 + aspeed_ast2700_e2m_ic_of_init); diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc.c --- a/drivers/irqchip/irq-aspeed-intc.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/irqchip/irq-aspeed-intc.c 2025-12-23 10:16:21.173031848 +0000 -@@ -0,0 +1,188 @@ ++++ b/drivers/irqchip/irq-aspeed-intc.c 2026-09-09 15:51:44.760237437 +0000 +@@ -0,0 +1,327 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Aspeed Interrupt Controller. @@ -39828,14 +40046,19 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + */ + +#include ++#include +#include +#include -+#include +#include ++#include ++#include ++#include +#include +#include +#include ++#include +#include ++#include + +#define INTC_INT_ENABLE_REG 0x00 +#define INTC_INT_STATUS_REG 0x04 @@ -39846,62 +40069,71 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + void __iomem *base; + raw_spinlock_t intc_lock; + struct irq_domain *irq_domain; ++ struct device_node *node; ++ unsigned int parent_irqs[INTC_IRQS_PER_WORD]; ++ unsigned int parent_irq_count; ++ struct kobject kobj; ++ struct list_head list; +}; + -+static void aspeed_intc0_ic_irq_handler(struct irq_desc *desc) ++static LIST_HEAD(aspeed_intc_instances); ++ ++/* ++ * INTC0 uses a 1:1 mapping between each parent GIC SPI line and one leaf ++ * interrupt bit. The leaf hwirq is derived directly from the parent GIC ++ * hwirq number, so no status register scan is needed (contrast with intc1 ++ * which aggregates multiple sources behind a single parent line). ++ */ ++static irqreturn_t aspeed_intc0_ic_irq_handler(int irq, void *dev_id) +{ -+ struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc); -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ struct irq_data *irq_data = irq_desc_get_irq_data(desc); ++ struct aspeed_intc_ic *intc_ic = dev_id; ++ struct irq_data *irq_data = irq_get_irq_data(irq); + unsigned long hwirq; + + if (!irq_data || !intc_ic) { + pr_err("Invalid irq_data or intc_ic\n"); -+ return; ++ return IRQ_NONE; + } + + if (irq_data->hwirq < INTC_IRQ_BASE + 32) { + pr_err("Invalid hwirq: %lu\n", irq_data->hwirq); -+ return; ++ return IRQ_NONE; + } + hwirq = irq_data->hwirq - INTC_IRQ_BASE - 32; /* 32 is SPI offset */ + -+ chained_irq_enter(chip, desc); -+ + generic_handle_domain_irq(intc_ic->irq_domain, hwirq); + + /* -+ * TODO: This a WA to prevnet potential race conditions when -+ * multiple interrupts are processed in multi-core environment. ++ * Serialize the status-clear to prevent potential race conditions ++ * when multiple interrupts are processed in a multi-core environment. + */ + raw_spin_lock(&intc_ic->intc_lock); + writel(BIT(hwirq), intc_ic->base + INTC_INT_STATUS_REG); + raw_spin_unlock(&intc_ic->intc_lock); + -+ chained_irq_exit(chip, desc); ++ return IRQ_HANDLED; +} + -+static void aspeed_intc1_ic_irq_handler(struct irq_desc *desc) ++static irqreturn_t aspeed_intc1_ic_irq_handler(int irq, void *dev_id) +{ -+ struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc); -+ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct aspeed_intc_ic *intc_ic = dev_id; + unsigned long bit, status; + + if (!intc_ic) { + pr_err("Invalid intc_ic\n"); -+ return; ++ return IRQ_NONE; + } + -+ chained_irq_enter(chip, desc); -+ + status = readl(intc_ic->base + INTC_INT_STATUS_REG); ++ if (!status) ++ return IRQ_NONE; + + for_each_set_bit(bit, &status, INTC_IRQS_PER_WORD) { + generic_handle_domain_irq(intc_ic->irq_domain, bit); + writel(BIT(bit), intc_ic->base + INTC_INT_STATUS_REG); + } + -+ chained_irq_exit(chip, desc); ++ return IRQ_HANDLED; +} + +static void aspeed_intc_irq_mask(struct irq_data *data) @@ -39909,7 +40141,7 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); + unsigned int mask; + -+ guard(raw_spinlock)(&intc_ic->intc_lock); ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); + mask = readl(intc_ic->base + INTC_INT_ENABLE_REG) & ~BIT(data->hwirq); + writel(mask, intc_ic->base + INTC_INT_ENABLE_REG); +} @@ -39919,15 +40151,26 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); + unsigned int unmask; + -+ guard(raw_spinlock)(&intc_ic->intc_lock); ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); + unmask = readl(intc_ic->base + INTC_INT_ENABLE_REG) | BIT(data->hwirq); + writel(unmask, intc_ic->base + INTC_INT_ENABLE_REG); +} + ++static void aspeed_intc_irq_print_chip(struct irq_data *data, struct seq_file *p) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ ++ if (intc_ic && intc_ic->node) ++ seq_printf(p, " %pOF", intc_ic->node); ++ else ++ seq_puts(p, " ASPEED INTC"); ++} ++ +static struct irq_chip aspeed_intc_chip = { + .name = "ASPEED INTC", + .irq_mask = aspeed_intc_irq_mask, + .irq_unmask = aspeed_intc_irq_unmask, ++ .irq_print_chip = aspeed_intc_irq_print_chip, +}; + +static int aspeed_intc_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq, @@ -39943,12 +40186,68 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + .map = aspeed_intc_ic_map_irq_domain, +}; + ++static ssize_t irq_groups_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ struct aspeed_intc_ic *intc = ++ container_of(kobj, struct aspeed_intc_ic, kobj); ++ ssize_t len = 0; ++ ++ if (intc->parent_irq_count == 1) { ++ /* Aggregated: one parent line serves all children. */ ++ len += sysfs_emit_at(buf, len, "group 0: parent_irq=%u members=", ++ intc->parent_irqs[0]); ++ for (int hwirq = 0; hwirq < INTC_IRQS_PER_WORD; hwirq++) { ++ unsigned int virq = irq_find_mapping(intc->irq_domain, hwirq); ++ ++ if (virq) ++ len += sysfs_emit_at(buf, len, "%u ", virq); ++ } ++ len += sysfs_emit_at(buf, len, "\n"); ++ } else { ++ /* 1:1: each parent serves one child (derived from GIC hwirq). */ ++ for (unsigned int i = 0; i < intc->parent_irq_count; i++) { ++ struct irq_data *pdata = irq_get_irq_data(intc->parent_irqs[i]); ++ unsigned int virq; ++ unsigned long phw; ++ ++ if (!pdata) ++ continue; ++ phw = pdata->hwirq; ++ if (phw < INTC_IRQ_BASE + 32) ++ continue; ++ virq = irq_find_mapping(intc->irq_domain, ++ phw - INTC_IRQ_BASE - 32); ++ if (!virq) ++ continue; ++ len += sysfs_emit_at(buf, len, ++ "group %u: parent_irq=%u members=%u\n", ++ i, intc->parent_irqs[i], virq); ++ } ++ } ++ return len; ++} ++ ++static struct kobj_attribute aspeed_intc_irq_groups_attr = __ATTR_RO(irq_groups); ++ ++static struct attribute *aspeed_intc_attrs[] = { ++ &aspeed_intc_irq_groups_attr.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(aspeed_intc); ++ ++static const struct kobj_type aspeed_intc_kobj_type = { ++ .sysfs_ops = &kobj_sysfs_ops, ++ .default_groups = aspeed_intc_groups, ++}; ++ +static int __init aspeed_intc_ic_of_init(struct device_node *node, + struct device_node *parent) +{ + struct aspeed_intc_ic *intc_ic; ++ irq_handler_t handler; + int ret = 0; -+ int irq, irq_count, i; ++ int irq, irq_count = 0, i; + + intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); + if (!intc_ic) @@ -39960,11 +40259,28 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + ret = -ENOMEM; + goto err_free_ic; + } ++ intc_ic->node = node; + writel(0xffffffff, intc_ic->base + INTC_INT_STATUS_REG); + writel(0x0, intc_ic->base + INTC_INT_ENABLE_REG); + -+ intc_ic->irq_domain = irq_domain_add_linear(node, INTC_IRQS_PER_WORD, -+ &aspeed_intc_ic_irq_domain_ops, intc_ic); ++ irq_count = of_irq_count(node); ++ if (irq_count == 0) { ++ pr_err("Failed to get irq count\n"); ++ ret = -EINVAL; ++ goto err_iounmap; ++ } ++ ++ if (irq_count > INTC_IRQS_PER_WORD) { ++ pr_err("Too many parent IRQs: %d\n", irq_count); ++ ret = -EINVAL; ++ goto err_iounmap; ++ } ++ ++ intc_ic->irq_domain = ++ irq_domain_create_linear(of_fwnode_handle(node), ++ INTC_IRQS_PER_WORD, ++ &aspeed_intc_ic_irq_domain_ops, ++ intc_ic); + if (!intc_ic->irq_domain) { + ret = -ENOMEM; + goto err_iounmap; @@ -39972,12 +40288,10 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + + raw_spin_lock_init(&intc_ic->intc_lock); + -+ irq_count = of_irq_count(node); -+ if (irq_count == 0) { -+ pr_err("Failed to get irq count\n"); -+ ret = -EINVAL; -+ goto err_iounmap; -+ } ++ if (irq_count > 1) ++ handler = aspeed_intc0_ic_irq_handler; ++ else ++ handler = aspeed_intc1_ic_irq_handler; + + for (i = 0; i < irq_count; i++) { + irq = irq_of_parse_and_map(node, i); @@ -39986,31 +40300,74 @@ diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc + ret = -EINVAL; + goto err_iounmap; + } else { -+ if (irq_count > 1) -+ irq_set_chained_handler_and_data(irq, aspeed_intc0_ic_irq_handler, intc_ic); -+ else -+ irq_set_chained_handler_and_data(irq, aspeed_intc1_ic_irq_handler, intc_ic); ++ ret = request_irq(irq, handler, IRQF_NO_THREAD, ++ "aspeed-intc", intc_ic); ++ if (ret) { ++ pr_err("Failed to request IRQ %d\n", irq); ++ irq_dispose_mapping(irq); ++ goto err_iounmap; ++ } ++ ++ intc_ic->parent_irqs[intc_ic->parent_irq_count++] = irq; + } + } + ++ list_add_tail(&intc_ic->list, &aspeed_intc_instances); ++ + return 0; + +err_iounmap: -+ for (i = 0; i < irq_count; i++) { -+ irq = irq_of_parse_and_map(node, i); -+ if (irq) -+ irq_dispose_mapping(irq); ++ for (i = 0; i < intc_ic->parent_irq_count; i++) { ++ free_irq(intc_ic->parent_irqs[i], intc_ic); ++ irq_dispose_mapping(intc_ic->parent_irqs[i]); + } ++ if (intc_ic->irq_domain) ++ irq_domain_remove(intc_ic->irq_domain); + iounmap(intc_ic->base); +err_free_ic: + kfree(intc_ic); + return ret; +} + ++/* ++ * IRQCHIP_DECLARE callbacks fire from init_IRQ(), which runs before ++ * kernel_kobj is created in core_initcall(ksysfs_init). Defer the sysfs ++ * setup until kernel_kobj is available so /sys/kernel/aspeed-intc-* can be ++ * created. The physical base address is appended to disambiguate multiple ++ * controllers that share a basename (e.g. nested LTPI controllers). ++ */ ++static int __init aspeed_intc_sysfs_init(void) ++{ ++ struct aspeed_intc_ic *intc; ++ struct resource res; ++ int ret; ++ ++ list_for_each_entry(intc, &aspeed_intc_instances, list) { ++ ret = of_address_to_resource(intc->node, 0, &res); ++ if (ret) { ++ pr_warn("Failed to get resource for %pOF: %d\n", ++ intc->node, ret); ++ continue; ++ } ++ ++ ret = kobject_init_and_add(&intc->kobj, &aspeed_intc_kobj_type, ++ kernel_kobj, "aspeed-intc-%pOFn@%llx", ++ intc->node, ++ (unsigned long long)res.start); ++ if (ret) { ++ pr_warn("Failed to create sysfs entry for %pOF: %d\n", ++ intc->node, ret); ++ kobject_put(&intc->kobj); ++ } ++ } ++ return 0; ++} ++late_initcall(aspeed_intc_sysfs_init); ++ +IRQCHIP_DECLARE(ast2700_intc_ic, "aspeed,ast2700-intc-ic", aspeed_intc_ic_of_init); diff --git a/drivers/irqchip/irq-aspeed-scu-ic.c b/drivers/irqchip/irq-aspeed-scu-ic.c ---- a/drivers/irqchip/irq-aspeed-scu-ic.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/irqchip/irq-aspeed-scu-ic.c 2025-12-23 10:16:21.177031781 +0000 +--- a/drivers/irqchip/irq-aspeed-scu-ic.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/irqchip/irq-aspeed-scu-ic.c 2026-09-09 15:51:44.764237376 +0000 @@ -1,61 +1,76 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* @@ -40379,51 +40736,781 @@ diff --git a/drivers/irqchip/irq-aspeed-scu-ic.c b/drivers/irqchip/irq-aspeed-sc +IRQCHIP_DECLARE(ast2700_scu_ic1, "aspeed,ast2700-scu-ic1", aspeed_scu_ic_of_init); +IRQCHIP_DECLARE(ast2700_scu_ic2, "aspeed,ast2700-scu-ic2", aspeed_scu_ic_of_init); +IRQCHIP_DECLARE(ast2700_scu_ic3, "aspeed,ast2700-scu-ic3", aspeed_scu_ic_of_init); -diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig ---- a/drivers/jtag/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/jtag/Kconfig 2025-12-23 10:16:17.210098268 +0000 -@@ -0,0 +1,31 @@ -+menuconfig JTAG -+ tristate "JTAG support" -+ help -+ This provides basic core functionality support for JTAG class devices. -+ Hardware that is equipped with a JTAG microcontroller can be -+ supported by using this driver's interfaces. -+ This driver exposes a set of IOCTLs to the user space for -+ the following commands: -+ SDR: Performs an IEEE 1149.1 Data Register scan -+ SIR: Performs an IEEE 1149.1 Instruction Register scan. -+ RUNTEST: Forces the IEEE 1149.1 bus to a run state for a specified -+ number of clocks or a specified time period. -+ -+ If you want this support, you should say Y here. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called jtag. -+ -+menuconfig JTAG_ASPEED -+ tristate "Aspeed SoC JTAG controller support" -+ depends on JTAG && HAS_IOMEM -+ depends on ARCH_ASPEED || COMPILE_TEST -+ help -+ This provides a support for Aspeed JTAG device, equipped on -+ Aspeed SoC 24xx and 25xx families. Drivers allows programming -+ of hardware devices, connected to SoC through the JTAG interface. -+ -+ If you want this support, you should say Y here. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called jtag-aspeed. -diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile ---- a/drivers/jtag/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/jtag/Makefile 2025-12-23 10:16:17.210098268 +0000 -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_JTAG) += jtag.o -+obj-$(CONFIG_JTAG_ASPEED) += jtag-aspeed.o +diff --git a/drivers/irqchip/irq-ast2700-intc0.c b/drivers/irqchip/irq-ast2700-intc0.c +--- a/drivers/irqchip/irq-ast2700-intc0.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/irqchip/irq-ast2700-intc0.c 2026-09-09 15:51:44.603239809 +0000 +@@ -0,0 +1,509 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Aspeed Interrupt Controller. ++ * ++ * Copyright (C) 2023 ASPEED Technology Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define INT_NUM 480 ++#define SWINT_NUM 16 ++#define INTM_NUM 50 ++ ++#define SWINT_BASE (INT_NUM) ++#define INTM_BASE (INT_NUM + SWINT_NUM) ++#define INT0_NUM (INT_NUM + SWINT_NUM + INTM_NUM) ++ ++#define GIC_P2P_SPI_END 128 ++#define GIC_SWINT_SPI_BASE 144 ++#define GIC_SWINT_SPI_NUM 16 ++#define GIC_INTM_SPI_BASE 192 ++ ++#define INTC0_SWINT_IER 0x10 ++#define INTC0_SWINT_ISR 0x14 ++#define INTC0_INTBANKX_IER 0x1000 ++#define INTC0_INTBANK_GROUPS 11 ++#define INTC0_INTBANKS_PER_GRP 3 ++#define INTC0_IMTMX_IER 0x1b00 ++#define INTC0_IMTMX_ISR 0x1b04 ++#define INTC0_IMTM_BANK_NUM 3 ++#define INTM_IRQS_PER_BANK 10 ++ ++struct intc0_pin_region { ++ u32 int_base; ++ u32 gic_base; ++ u32 cnt; ++}; ++ ++struct aspeed_intc_ic { ++ void __iomem *base; ++ raw_spinlock_t intc_lock; ++ struct irq_domain *irq_domain; ++ struct intc0_pin_region *pin_region; ++ int pin_region_cnt; ++}; ++ ++static void aspeed_swint_irq_mask(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bit = data->hwirq - SWINT_BASE; ++ unsigned int mask; ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ mask = readl(intc_ic->base + INTC0_SWINT_IER) & ~BIT(bit); ++ writel(mask, intc_ic->base + INTC0_SWINT_IER); ++ irq_chip_mask_parent(data); ++} ++ ++static void aspeed_swint_irq_unmask(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bit = data->hwirq - SWINT_BASE; ++ unsigned int unmask; ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ unmask = readl(intc_ic->base + INTC0_SWINT_IER) | BIT(bit); ++ writel(unmask, intc_ic->base + INTC0_SWINT_IER); ++ irq_chip_unmask_parent(data); ++} ++ ++static void aspeed_swint_irq_eoi(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bit = data->hwirq - SWINT_BASE; ++ ++ writel(BIT(bit), intc_ic->base + INTC0_SWINT_ISR); ++ irq_chip_eoi_parent(data); ++} ++ ++static struct irq_chip aspeed_swint_chip = { ++ .name = "ast2700-swint", ++ .irq_eoi = aspeed_swint_irq_eoi, ++ .irq_mask = aspeed_swint_irq_mask, ++ .irq_unmask = aspeed_swint_irq_unmask, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .flags = IRQCHIP_SET_TYPE_MASKED, ++}; ++ ++static void aspeed_intc0_irq_mask(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK; ++ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK; ++ unsigned int mask; ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ mask = readl(intc_ic->base + INTC0_IMTMX_IER + bank * 0x10) & ~BIT(bit); ++ writel(mask, intc_ic->base + INTC0_IMTMX_IER + bank * 0x10); ++ irq_chip_mask_parent(data); ++} ++ ++static void aspeed_intc0_irq_unmask(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK; ++ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK; ++ unsigned int unmask; ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ unmask = readl(intc_ic->base + INTC0_IMTMX_IER + bank * 0x10) | BIT(bit); ++ writel(unmask, intc_ic->base + INTC0_IMTMX_IER + bank * 0x10); ++ irq_chip_unmask_parent(data); ++} ++ ++static void aspeed_intc0_irq_eoi(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK; ++ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK; ++ ++ /* ++ * TODO: This a WA to prevnet potential race conditions when ++ * multiple interrupts are processed in multi-core environment. ++ */ ++ raw_spin_lock(&intc_ic->intc_lock); ++ writel(BIT(bit), intc_ic->base + INTC0_IMTMX_ISR + bank * 0x10); ++ raw_spin_unlock(&intc_ic->intc_lock); ++ ++ irq_chip_eoi_parent(data); ++} ++ ++static struct irq_chip aspeed_intm_chip = { ++ .name = "ast2700-intmerge", ++ .irq_eoi = aspeed_intc0_irq_eoi, ++ .irq_mask = aspeed_intc0_irq_mask, ++ .irq_unmask = aspeed_intc0_irq_unmask, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .flags = IRQCHIP_SET_TYPE_MASKED, ++ ++}; ++ ++static struct irq_chip linear_intr_irq_chip = { ++ .name = "ast2700-int", ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .flags = IRQCHIP_SET_TYPE_MASKED, ++}; ++ ++static int aspeed_intc_ic0_map_irq_domain(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ if (hwirq < GIC_P2P_SPI_END) ++ irq_set_chip_and_handler(irq, &linear_intr_irq_chip, handle_level_irq); ++ else if (hwirq < SWINT_BASE) ++ return -EINVAL; ++ else if (hwirq < INTM_BASE) ++ irq_set_chip_and_handler(irq, &aspeed_swint_chip, handle_level_irq); ++ else if (hwirq < INT0_NUM) ++ irq_set_chip_and_handler(irq, &aspeed_intm_chip, handle_level_irq); ++ else ++ return -EINVAL; ++ ++ irq_set_chip_data(irq, domain->host_data); ++ return 0; ++} ++ ++static int aspeed_intc0_irq_domain_translate(struct irq_domain *domain, ++ struct irq_fwspec *fwspec, ++ unsigned long *hwirq, ++ unsigned int *type) ++{ ++ if (fwspec->param_count != 1) ++ return -EINVAL; ++ ++ *hwirq = fwspec->param[0]; ++ *type = IRQ_TYPE_NONE; ++ return 0; ++} ++ ++static int get_parent_hwirq(struct aspeed_intc_ic *intc_ic, ++ u32 local_hwirq, ++ irq_hw_number_t *parent_hwirq) ++{ ++ int i; ++ ++ for (i = 0; i < intc_ic->pin_region_cnt; i++) { ++ u32 int_base = intc_ic->pin_region[i].int_base; ++ u32 cnt = intc_ic->pin_region[i].cnt; ++ ++ if (local_hwirq >= int_base && local_hwirq < int_base + cnt) { ++ *parent_hwirq = intc_ic->pin_region[i].gic_base + ++ (local_hwirq - int_base); ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int aspeed_intc0_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *data) ++{ ++ struct aspeed_intc_ic *intc_ic = domain->host_data; ++ struct irq_fwspec *fwspec = data; ++ struct irq_fwspec parent_fwspec; ++ irq_hw_number_t parent_hwirq; ++ struct irq_chip *chip; ++ unsigned long hwirq; ++ unsigned int type; ++ int ret; ++ ++ ret = aspeed_intc0_irq_domain_translate(domain, fwspec, &hwirq, &type); ++ if (ret) ++ return ret; ++ ++ if (hwirq >= GIC_P2P_SPI_END && hwirq < INT_NUM) ++ return -EINVAL; ++ ++ if (hwirq < SWINT_BASE) ++ chip = &linear_intr_irq_chip; ++ else if (hwirq < INTM_BASE) ++ chip = &aspeed_swint_chip; ++ else ++ chip = &aspeed_intm_chip; ++ ++ ret = get_parent_hwirq(intc_ic, (u32)hwirq, &parent_hwirq); ++ if (ret) ++ return irq_domain_disconnect_hierarchy(domain->parent, virq); ++ ++ parent_fwspec.fwnode = domain->parent->fwnode; ++ parent_fwspec.param_count = 3; ++ parent_fwspec.param[0] = GIC_SPI; ++ parent_fwspec.param[1] = parent_hwirq; ++ parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; ++ ++ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); ++ if (ret) ++ return ret; ++ ++ for (int i = 0; i < nr_irqs; ++i, ++hwirq, ++virq) { ++ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, ++ chip, ++ domain->host_data); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int aspeed_intc0_irq_domain_activate(struct irq_domain *domain, ++ struct irq_data *data, bool reserve) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ ++ if (data->hwirq < GIC_P2P_SPI_END) { ++ int bank = data->hwirq / 32; ++ int bit = data->hwirq % 32; ++ u32 mask = BIT(bit); ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ for (int i = 0; i < 3; i++) { ++ void __iomem *sel = intc_ic->base + 0x200 + bank * 4 + 0x100 * i; ++ ++ if (readl(sel) & mask) { ++ writel(readl(sel) & ~mask, sel); ++ if (readl(sel) & mask) ++ return -EACCES; ++ } ++ } ++ } else if (data->hwirq < INT_NUM) { ++ return -EINVAL; ++ } else if (data->hwirq < INT0_NUM) { ++ return 0; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops aspeed_intc0_ic_irq_domain_ops = { ++ .translate = aspeed_intc0_irq_domain_translate, ++ .alloc = aspeed_intc0_irq_domain_alloc, ++ .free = irq_domain_free_irqs_common, ++ .map = aspeed_intc_ic0_map_irq_domain, ++ .activate = aspeed_intc0_irq_domain_activate, ++}; ++ ++static int aspeed_intc0_init_gic_ranges(struct aspeed_intc_ic *intc_ic, ++ struct device_node *node, ++ struct device_node *parent_node) ++{ ++ struct intc0_pin_region *pin_region; ++ int region_cnt = 0; ++ int i, n, ret; ++ ++ if (!of_device_is_compatible(parent_node, "arm,gic-v3")) ++ return -ENOENT; ++ ++ n = of_property_count_elems_of_size(node, "aspeed,interrupt-ranges", sizeof(u32)); ++ if (n <= 0 || n % 6) ++ return -EINVAL; ++ ++ /* ++ * Each range is described as: ++ * ++ * and we only care about ranges whose phandle matches ++ * this controller's interrupt-parent (&gic). ++ */ ++ for (i = 0; i < n / 6; i++) { ++ struct device_node *target; ++ phandle parent_handle; ++ u32 gic_type; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 2, &parent_handle); ++ if (ret) ++ return ret; ++ ++ target = of_find_node_by_phandle(parent_handle); ++ if (!target) ++ continue; ++ ++ if (target != parent_node) { ++ of_node_put(target); ++ continue; ++ } ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 3, &gic_type); ++ of_node_put(target); ++ if (ret) ++ return ret; ++ ++ if (gic_type != GIC_SPI) ++ continue; ++ ++ region_cnt++; ++ } ++ ++ if (!region_cnt) ++ return -EINVAL; ++ ++ pin_region = kcalloc(region_cnt, sizeof(*pin_region), GFP_KERNEL); ++ if (!pin_region) ++ return -ENOMEM; ++ ++ intc_ic->pin_region_cnt = region_cnt; ++ intc_ic->pin_region = pin_region; ++ ++ region_cnt = 0; ++ for (i = 0; i < n / 6; i++) { ++ struct device_node *target; ++ phandle parent_handle; ++ u32 gic_flags; ++ u32 gic_type; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 2, &parent_handle); ++ if (ret) ++ return ret; ++ ++ target = of_find_node_by_phandle(parent_handle); ++ if (!target) ++ continue; ++ ++ if (target != parent_node) { ++ of_node_put(target); ++ continue; ++ } ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 0, ++ &pin_region[region_cnt].int_base); ++ if (ret) ++ goto out_put; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 1, ++ &pin_region[region_cnt].cnt); ++ if (ret) ++ goto out_put; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 3, &gic_type); ++ if (ret) ++ goto out_put; ++ ++ if (gic_type != GIC_SPI) ++ goto out_put; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 4, ++ &pin_region[region_cnt].gic_base); ++ if (ret) ++ goto out_put; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 6 + 5, &gic_flags); ++ if (ret) ++ goto out_put; ++ ++ if (gic_flags != IRQ_TYPE_LEVEL_HIGH) ++ goto out_put; ++ ++ region_cnt++; ++out_put: ++ of_node_put(target); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void aspeed_intc0_disable_swint(struct aspeed_intc_ic *intc_ic) ++{ ++ writel(0, intc_ic->base + INTC0_SWINT_IER); ++} ++ ++static void aspeed_intc0_disable_intbank(struct aspeed_intc_ic *intc_ic) ++{ ++ int i, j; ++ ++ for (i = 0; i < INTC0_INTBANK_GROUPS; i++) { ++ for (j = 0; j < INTC0_INTBANKS_PER_GRP; j++) { ++ u32 base = INTC0_INTBANKX_IER + (0x100 * i) + (0x10 * j); ++ ++ writel(0, intc_ic->base + base); ++ } ++ } ++} ++ ++static void aspeed_intc0_disable_intm(struct aspeed_intc_ic *intc_ic) ++{ ++ int i; ++ ++ for (i = 0; i < INTC0_IMTM_BANK_NUM; i++) ++ writel(0, intc_ic->base + INTC0_IMTMX_IER + (0x10 * i)); ++} ++ ++static int aspeed_intc0_ic_of_init(struct device_node *node, struct device_node *parent) ++{ ++ struct irq_domain *parent_domain; ++ struct aspeed_intc_ic *intc_ic; ++ int ret; ++ ++ if (!parent) { ++ pr_err("missing parent interrupt node\n"); ++ return -ENODEV; ++ } ++ ++ intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); ++ if (!intc_ic) ++ return -ENOMEM; ++ ++ intc_ic->base = of_iomap(node, 0); ++ if (!intc_ic->base) { ++ ret = -ENOMEM; ++ goto err_free_ic; ++ } ++ ++ aspeed_intc0_disable_swint(intc_ic); ++ aspeed_intc0_disable_intbank(intc_ic); ++ aspeed_intc0_disable_intm(intc_ic); ++ ++ raw_spin_lock_init(&intc_ic->intc_lock); ++ ++ parent_domain = irq_find_host(parent); ++ if (!parent_domain) { ++ pr_err("unable to obtain parent domain\n"); ++ return -ENODEV; ++ } ++ ++ intc_ic->irq_domain = irq_domain_create_hierarchy(parent_domain, 0, INT0_NUM, ++ of_fwnode_handle(node), ++ &aspeed_intc0_ic_irq_domain_ops, ++ intc_ic); ++ if (!intc_ic->irq_domain) { ++ ret = -ENOMEM; ++ goto err_ioumap; ++ } ++ ++ ret = aspeed_intc0_init_gic_ranges(intc_ic, node, parent); ++ if (ret < 0) ++ goto err_ioumap; ++ ++ return 0; ++ ++err_ioumap: ++ iounmap(intc_ic->base); ++err_free_ic: ++ kfree(intc_ic); ++ return ret; ++} ++ ++IRQCHIP_DECLARE(ast2700_intc0_ic, "aspeed,ast2700-intc0-ic", aspeed_intc0_ic_of_init); +diff --git a/drivers/irqchip/irq-ast2700-intc1.c b/drivers/irqchip/irq-ast2700-intc1.c +--- a/drivers/irqchip/irq-ast2700-intc1.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/irqchip/irq-ast2700-intc1.c 2026-09-09 15:51:44.596239915 +0000 +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Aspeed Interrupt Controller. ++ * ++ * Copyright (C) 2023 ASPEED Technology Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define INTC1_IER 0x100 ++#define INTC1_ISR 0x104 ++#define INTC1_IRQS_PER_BANK 32 ++#define INTC1_BANK_NUM 6 ++ ++struct aspeed_intc_ic { ++ void __iomem *base; ++ raw_spinlock_t intc_lock; ++ struct irq_domain *irq_domain; ++}; ++ ++static void aspeed_intc1_ic_irq_handler(struct irq_desc *desc) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned long bit, status; ++ ++ chained_irq_enter(chip, desc); ++ ++ for (int bank = 0; bank < INTC1_BANK_NUM; bank++) { ++ status = readl(intc_ic->base + INTC1_ISR + (0x10 * bank)); ++ if (!status) ++ continue; ++ ++ for_each_set_bit(bit, &status, INTC1_IRQS_PER_BANK) { ++ generic_handle_domain_irq(intc_ic->irq_domain, ++ (bank * INTC1_IRQS_PER_BANK) + bit); ++ writel(BIT(bit), intc_ic->base + INTC1_ISR + (0x10 * bank)); ++ } ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static void aspeed_intc1_irq_mask(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bit = data->hwirq % INTC1_IRQS_PER_BANK; ++ int bank = data->hwirq / INTC1_IRQS_PER_BANK; ++ unsigned int mask; ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ mask = readl(intc_ic->base + INTC1_IER + (0x10 * bank)) & ~BIT(bit); ++ writel(mask, intc_ic->base + INTC1_IER + (0x10 * bank)); ++} ++ ++static void aspeed_intc1_irq_unmask(struct irq_data *data) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bit = data->hwirq % INTC1_IRQS_PER_BANK; ++ int bank = data->hwirq / INTC1_IRQS_PER_BANK; ++ unsigned int unmask; ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ unmask = readl(intc_ic->base + INTC1_IER + (0x10 * bank)) | BIT(bit); ++ writel(unmask, intc_ic->base + INTC1_IER + (0x10 * bank)); ++} ++ ++static struct irq_chip aspeed_intc_chip = { ++ .name = "ASPEED INTC1", ++ .irq_mask = aspeed_intc1_irq_mask, ++ .irq_unmask = aspeed_intc1_irq_unmask, ++}; ++ ++static int aspeed_intc1_irq_domain_translate(struct irq_domain *domain, struct irq_fwspec *fwspec, ++ unsigned long *hwirq, unsigned int *type) ++{ ++ if (fwspec->param_count != 1) ++ return -EINVAL; ++ ++ *hwirq = fwspec->param[0]; ++ *type = IRQ_TYPE_LEVEL_HIGH; ++ return 0; ++} ++ ++static int aspeed_intc1_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_domain_set_info(domain, irq, hwirq, &aspeed_intc_chip, ++ domain->host_data, handle_level_irq, NULL, NULL); ++ return 0; ++} ++ ++static int aspeed_intc1_irq_domain_activate(struct irq_domain *domain, ++ struct irq_data *data, bool reserve) ++{ ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ int bank = data->hwirq / INTC1_IRQS_PER_BANK; ++ int bit = data->hwirq % INTC1_IRQS_PER_BANK; ++ u32 mask = BIT(bit); ++ ++ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); ++ for (int i = 0; i < 3; i++) { ++ void __iomem *sel = intc_ic->base + 0x80 + bank * 4 + 0x20 * i; ++ ++ if (readl(sel) & mask) { ++ writel(readl(sel) & ~mask, sel); ++ if (readl(sel) & mask) ++ return -EACCES; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops aspeed_intc1_ic_irq_domain_ops = { ++ .map = aspeed_intc1_ic_map_irq_domain, ++ .translate = aspeed_intc1_irq_domain_translate, ++ .activate = aspeed_intc1_irq_domain_activate, ++}; ++ ++static int aspeed_intc1_interrupt_ranges(struct aspeed_intc_ic *intc_ic, ++ struct device_node *node, ++ struct device_node *parent_node) ++{ ++ struct of_phandle_args parent_irq; ++ int i, j, n, ret; ++ ++ if (!of_device_is_compatible(parent_node, "aspeed,ast2700-intc0-ic")) ++ return -ENOENT; ++ ++ n = of_property_count_elems_of_size(node, "aspeed,interrupt-ranges", sizeof(u32)); ++ if (n <= 0 || n % 4) ++ return -EINVAL; ++ ++ /* ++ * Each range is described as: ++ * ++ * and we only care about ranges whose phandle matches ++ * this controller's interrupt-parent (&intc0). ++ */ ++ for (i = 0; i < n / 4; i++) { ++ struct device_node *target; ++ phandle parent_handle; ++ u32 base_irq; ++ u32 count; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 4 + 2, &parent_handle); ++ if (ret) ++ return ret; ++ ++ target = of_find_node_by_phandle(parent_handle); ++ if (!target) ++ continue; ++ ++ if (target != parent_node) { ++ of_node_put(target); ++ continue; ++ } ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 4 + 1, &count); ++ if (ret) ++ return ret; ++ ++ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", ++ i * 4 + 3, &base_irq); ++ if (ret) ++ return ret; ++ ++ for (j = 0; j < count; j++) { ++ int irq; ++ ++ parent_irq.np = parent_node; ++ parent_irq.args_count = 1; ++ parent_irq.args[0] = base_irq + j; ++ irq = irq_create_of_mapping(&parent_irq); ++ if (!irq) ++ continue; ++ ++ irq_set_chained_handler_and_data(irq, ++ aspeed_intc1_ic_irq_handler, ++ intc_ic); ++ } ++ ++ of_node_put(target); ++ } ++ ++ return 0; ++} ++ ++static void aspeed_intc1_disable_int(struct aspeed_intc_ic *intc_ic) ++{ ++ for (int i = 0; i < INTC1_BANK_NUM; i++) ++ writel(0x0, intc_ic->base + INTC1_IER + (0x10 * i)); ++} ++ ++static int aspeed_intc1_ic_of_init(struct device_node *node, struct device_node *parent) ++{ ++ struct aspeed_intc_ic *intc_ic; ++ int ret = 0; ++ ++ if (!parent) { ++ pr_err("missing parent interrupt node\n"); ++ return -ENODEV; ++ } ++ ++ if (!irq_find_host(parent)) ++ return -ENODEV; ++ ++ intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); ++ ++ if (!intc_ic) ++ return -ENOMEM; ++ ++ intc_ic->base = of_iomap(node, 0); ++ if (!intc_ic->base) { ++ pr_err("Failed to iomap intc_ic base\n"); ++ ret = -ENOMEM; ++ goto err_free_ic; ++ } ++ ++ raw_spin_lock_init(&intc_ic->intc_lock); ++ ++ aspeed_intc1_disable_int(intc_ic); ++ intc_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), ++ INTC1_BANK_NUM * INTC1_IRQS_PER_BANK, ++ &aspeed_intc1_ic_irq_domain_ops, intc_ic); ++ if (!intc_ic->irq_domain) { ++ ret = -ENOMEM; ++ goto err_iounmap; ++ } ++ ++ ret = aspeed_intc1_interrupt_ranges(intc_ic, node, parent); ++ if (ret < 0) ++ goto err_iounmap; ++ ++ return 0; ++ ++err_iounmap: ++ iounmap(intc_ic->base); ++err_free_ic: ++ kfree(intc_ic); ++ return ret; ++} ++ ++IRQCHIP_DECLARE(ast2700_intc1_ic, "aspeed,ast2700-intc1-ic", aspeed_intc1_ic_of_init); diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c --- a/drivers/jtag/jtag-aspeed.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/jtag/jtag-aspeed.c 2025-12-23 10:16:20.997034798 +0000 -@@ -0,0 +1,1657 @@ ++++ b/drivers/jtag/jtag-aspeed.c 2026-09-09 15:51:44.571240293 +0000 +@@ -0,0 +1,1692 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Mellanox Technologies. All rights reserved. +// Copyright (c) 2018 Oleksandr Shamray @@ -40432,6 +41519,7 @@ diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c +#include +#include +#include ++#include +#include +#include +#include @@ -40588,6 +41676,9 @@ diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c +/* Use this macro to set us delay for JTAG Master Controller to be programmed */ +#define AST26XX_JTAG_CTRL_UDELAY 2 + ++/* Timeout (us) for a GBLCTRL FIFO mode/reset state change to settle */ ++#define ASPEED_JTAG_FIFO_POLL_TIMEOUT_US 1000 ++ +#define DEBUG_JTAG + +static const char * const regnames[] = { @@ -41562,6 +42653,7 @@ diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c + u32 shift_bits; + u32 data_reg; + u32 reg_val; ++ u32 poll_val; + enum jtag_tapstate shift; + enum jtag_tapstate exit; + enum jtag_tapstate exitx; @@ -41646,14 +42738,44 @@ diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c + partial_xfer = partial_xfer_size; + + reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ ++ /* ++ * The FIFO must only be reset while it is in CPU mode; ++ * asserting RESET_FIFO in controller mode corrupts the data ++ * of subsequent transfers. Whether the FIFO is in CPU or ++ * controller mode is decided by the hardware itself and ++ * FIFO_CTRL_MODE is read-only, so wait for the hardware to ++ * report CPU mode (0) before asserting RESET_FIFO. ++ */ ++ ret = read_poll_timeout(aspeed_jtag_read, poll_val, ++ !(poll_val & ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE), ++ 0, ASPEED_JTAG_FIFO_POLL_TIMEOUT_US, false, ++ aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ if (ret) { ++ dev_err(aspeed_jtag->dev, ++ "timed out waiting for FIFO to return to CPU mode\n"); ++ return ret; ++ } ++ ++ /* CPU mode confirmed; it is now safe to reset the FIFO. */ + aspeed_jtag_write(aspeed_jtag, reg_val | + ASPEED_JTAG_GBLCTRL_RESET_FIFO, + ASPEED_JTAG_GBLCTRL); + -+ /* Switch internal FIFO into CPU mode */ -+ reg_val = reg_val & ~BIT(24); -+ aspeed_jtag_write(aspeed_jtag, reg_val, -+ ASPEED_JTAG_GBLCTRL); ++ /* ++ * RESET_FIFO is self-clearing; wait for it to read back as 0 ++ * so the FIFO is guaranteed flushed before we start loading ++ * data into it. ++ */ ++ ret = read_poll_timeout(aspeed_jtag_read, poll_val, ++ !(poll_val & ASPEED_JTAG_GBLCTRL_RESET_FIFO), ++ 0, ASPEED_JTAG_FIFO_POLL_TIMEOUT_US, false, ++ aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ if (ret) { ++ dev_err(aspeed_jtag->dev, ++ "timed out waiting for FIFO reset to clear\n"); ++ return ret; ++ } + + while (partial_xfer) { + if (partial_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) @@ -42081,425 +43203,9 @@ diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c +MODULE_AUTHOR("Oleksandr Shamray "); +MODULE_DESCRIPTION("ASPEED JTAG driver"); +MODULE_LICENSE("GPL v2"); -diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c ---- a/drivers/jtag/jtag.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/jtag/jtag.c 2025-12-23 10:16:17.210098268 +0000 -@@ -0,0 +1,387 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+// Copyright (c) 2018 Mellanox Technologies. All rights reserved. -+// Copyright (c) 2018 Oleksandr Shamray -+// Copyright (c) 2019 Intel Corporation -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static char *end_status_str[] = { "tlr", "idle", "selDR", "capDR", "sDR", -+ "ex1DR", "pDR", "ex2DR", "updDR", "selIR", -+ "capIR", "sIR", "ex1IR", "pIR", "ex2IR", -+ "updIR", "current" }; -+ -+struct jtag { -+ struct miscdevice miscdev; -+ const struct jtag_ops *ops; -+ int id; -+ unsigned long *priv; -+}; -+ -+static DEFINE_IDA(jtag_ida); -+ -+void *jtag_priv(struct jtag *jtag) -+{ -+ return jtag->priv; -+} -+EXPORT_SYMBOL_GPL(jtag_priv); -+ -+static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct jtag *jtag = file->private_data; -+ struct jtag_tap_state tapstate; -+ struct jtag_xfer xfer; -+ struct bitbang_packet bitbang; -+ struct tck_bitbang *bitbang_data; -+ struct jtag_mode mode; -+ u8 *xfer_data; -+ u32 data_size; -+ u32 value; -+ u32 active; -+ int err; -+ -+ if (!arg) -+ return -EINVAL; -+ -+ switch (cmd) { -+ case JTAG_GIOCFREQ: -+ if (!jtag->ops->freq_get) -+ return -EOPNOTSUPP; -+ -+ err = jtag->ops->freq_get(jtag, &value); -+ if (err) -+ break; -+ dev_dbg(jtag->miscdev.parent, "JTAG_GIOCFREQ: freq get = %d", -+ value); -+ -+ if (put_user(value, (__u32 __user *)arg)) -+ err = -EFAULT; -+ break; -+ -+ case JTAG_SIOCFREQ: -+ if (!jtag->ops->freq_set) -+ return -EOPNOTSUPP; -+ -+ if (get_user(value, (__u32 __user *)arg)) -+ return -EFAULT; -+ if (value == 0) -+ return -EINVAL; -+ -+ err = jtag->ops->freq_set(jtag, value); -+ dev_dbg(jtag->miscdev.parent, "JTAG_SIOCFREQ: freq set = %d", -+ value); -+ break; -+ -+ case JTAG_SIOCSTATE: -+ if (copy_from_user(&tapstate, (const void __user *)arg, -+ sizeof(struct jtag_tap_state))) -+ return -EFAULT; -+ -+ if (tapstate.from > JTAG_STATE_CURRENT) -+ return -EINVAL; -+ -+ if (tapstate.endstate > JTAG_STATE_CURRENT) -+ return -EINVAL; -+ -+ if (tapstate.reset > JTAG_FORCE_RESET) -+ return -EINVAL; -+ -+ dev_dbg(jtag->miscdev.parent, -+ "JTAG_SIOCSTATE: status set from %s to %s reset %d tck %d", -+ end_status_str[tapstate.from], -+ end_status_str[tapstate.endstate], tapstate.reset, -+ tapstate.tck); -+ -+ err = jtag->ops->status_set(jtag, &tapstate); -+ break; -+ -+ case JTAG_IOCXFER: -+ { -+ u8 ubit_mask = GENMASK(7, 0); -+ u8 remaining_bits = 0x0; -+ union pad_config padding; -+ -+ if (copy_from_user(&xfer, (const void __user *)arg, -+ sizeof(struct jtag_xfer))) -+ return -EFAULT; -+ -+ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) -+ return -EINVAL; -+ -+ if (xfer.type > JTAG_SDR_XFER) -+ return -EINVAL; -+ -+ if (xfer.direction > JTAG_READ_WRITE_XFER) -+ return -EINVAL; -+ -+ if (xfer.from > JTAG_STATE_CURRENT) -+ return -EINVAL; -+ -+ if (xfer.endstate > JTAG_STATE_CURRENT) -+ return -EINVAL; -+ -+ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); -+ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); -+ -+ /* Save unused remaining bits in this transfer */ -+ if ((xfer.length % BITS_PER_BYTE)) { -+ ubit_mask = GENMASK((xfer.length % BITS_PER_BYTE) - 1, -+ 0); -+ remaining_bits = xfer_data[data_size - 1] & ~ubit_mask; -+ } -+ -+ if (IS_ERR(xfer_data)) -+ return -EFAULT; -+ padding.int_value = xfer.padding; -+ dev_dbg(jtag->miscdev.parent, -+ "JTAG_IOCXFER: type: %s direction: %d, END : %s, padding: (value: %d) pre_pad: %d post_pad: %d, len: %d\n", -+ xfer.type ? "DR" : "IR", xfer.direction, -+ end_status_str[xfer.endstate], padding.pad_data, -+ padding.pre_pad_number, padding.post_pad_number, -+ xfer.length); -+ -+ print_hex_dump_debug("I:", DUMP_PREFIX_NONE, 16, 1, xfer_data, -+ data_size, false); -+ -+ err = jtag->ops->xfer(jtag, &xfer, xfer_data); -+ if (err) { -+ kfree(xfer_data); -+ return err; -+ } -+ -+ print_hex_dump_debug("O:", DUMP_PREFIX_NONE, 16, 1, xfer_data, -+ data_size, false); -+ -+ /* Restore unused remaining bits in this transfer */ -+ xfer_data[data_size - 1] = (xfer_data[data_size - 1] -+ & ubit_mask) | remaining_bits; -+ -+ err = copy_to_user(u64_to_user_ptr(xfer.tdio), -+ (void *)xfer_data, data_size); -+ kfree(xfer_data); -+ if (err) -+ return -EFAULT; -+ -+ if (copy_to_user((void __user *)arg, (void *)&xfer, -+ sizeof(struct jtag_xfer))) -+ return -EFAULT; -+ break; -+ } -+ -+ case JTAG_GIOCSTATUS: -+ err = jtag->ops->status_get(jtag, &value); -+ if (err) -+ break; -+ dev_dbg(jtag->miscdev.parent, "JTAG_GIOCSTATUS: status get %s", -+ end_status_str[value]); -+ -+ err = put_user(value, (__u32 __user *)arg); -+ break; -+ case JTAG_IOCBITBANG: -+ if (copy_from_user(&bitbang, (const void __user *)arg, -+ sizeof(struct bitbang_packet))) -+ return -EFAULT; -+ -+ if (bitbang.length >= JTAG_MAX_XFER_DATA_LEN) -+ return -EINVAL; -+ -+ data_size = bitbang.length * sizeof(struct tck_bitbang); -+ bitbang_data = memdup_user((void __user *)bitbang.data, -+ data_size); -+ if (IS_ERR(bitbang_data)) -+ return -EFAULT; -+ -+ err = jtag->ops->bitbang(jtag, &bitbang, bitbang_data); -+ if (err) { -+ kfree(bitbang_data); -+ return err; -+ } -+ err = copy_to_user((void __user *)bitbang.data, -+ (void *)bitbang_data, data_size); -+ kfree(bitbang_data); -+ if (err) -+ return -EFAULT; -+ break; -+ case JTAG_SIOCMODE: -+ if (!jtag->ops->mode_set) -+ return -EOPNOTSUPP; -+ -+ if (copy_from_user(&mode, (const void __user *)arg, -+ sizeof(struct jtag_mode))) -+ return -EFAULT; -+ -+ dev_dbg(jtag->miscdev.parent, -+ "JTAG_SIOCMODE: mode set feature %d mode %d", -+ mode.feature, mode.mode); -+ err = jtag->ops->mode_set(jtag, &mode); -+ break; -+ case JTAG_SIOCTRST: -+ if (!jtag->ops->trst_set) -+ return -EOPNOTSUPP; -+ -+ if (get_user(active, (__u32 __user *)arg)) -+ return -EFAULT; -+ -+ dev_dbg(jtag->miscdev.parent, -+ "JTAG_SIOCTRST: active %d", active); -+ -+ err = jtag->ops->trst_set(jtag, active); -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ return err; -+} -+ -+static int jtag_open(struct inode *inode, struct file *file) -+{ -+ struct jtag *jtag = container_of(file->private_data, -+ struct jtag, -+ miscdev); -+ -+ file->private_data = jtag; -+ if (jtag->ops->enable(jtag)) -+ return -EBUSY; -+ return nonseekable_open(inode, file); -+} -+ -+static int jtag_release(struct inode *inode, struct file *file) -+{ -+ struct jtag *jtag = file->private_data; -+ -+ if (jtag->ops->disable(jtag)) -+ return -EBUSY; -+ return 0; -+} -+ -+static const struct file_operations jtag_fops = { -+ .owner = THIS_MODULE, -+ .open = jtag_open, -+ .llseek = noop_llseek, -+ .unlocked_ioctl = jtag_ioctl, -+ .release = jtag_release, -+}; -+ -+struct jtag *jtag_alloc(struct device *host, size_t priv_size, -+ const struct jtag_ops *ops) -+{ -+ struct jtag *jtag; -+ -+ if (!host) -+ return NULL; -+ -+ if (!ops) -+ return NULL; -+ -+ if (!ops->status_set || !ops->status_get || !ops->xfer) -+ return NULL; -+ -+ jtag = kzalloc(sizeof(*jtag), GFP_KERNEL); -+ if (!jtag) -+ return NULL; -+ jtag->priv = kzalloc(priv_size, GFP_KERNEL); -+ if (!jtag->priv) -+ return NULL; -+ -+ jtag->ops = ops; -+ jtag->miscdev.parent = host; -+ -+ return jtag; -+} -+EXPORT_SYMBOL_GPL(jtag_alloc); -+ -+void jtag_free(struct jtag *jtag) -+{ -+ kfree(jtag); -+} -+EXPORT_SYMBOL_GPL(jtag_free); -+ -+static int jtag_register(struct jtag *jtag) -+{ -+ struct device *dev = jtag->miscdev.parent; -+ int err; -+ int id; -+ -+ if (!dev) -+ return -ENODEV; -+ -+ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); -+ if (id < 0) -+ return id; -+ -+ jtag->id = id; -+ -+ jtag->miscdev.fops = &jtag_fops; -+ jtag->miscdev.minor = MISC_DYNAMIC_MINOR; -+ jtag->miscdev.name = kasprintf(GFP_KERNEL, "jtag%d", id); -+ if (!jtag->miscdev.name) { -+ err = -ENOMEM; -+ goto err_jtag_alloc; -+ } -+ -+ err = misc_register(&jtag->miscdev); -+ if (err) { -+ dev_err(jtag->miscdev.parent, "Unable to register device\n"); -+ goto err_jtag_name; -+ } -+ return 0; -+ -+err_jtag_name: -+ kfree(jtag->miscdev.name); -+err_jtag_alloc: -+ ida_simple_remove(&jtag_ida, id); -+ return err; -+} -+ -+static void jtag_unregister(struct jtag *jtag) -+{ -+ misc_deregister(&jtag->miscdev); -+ kfree(jtag->miscdev.name); -+ ida_simple_remove(&jtag_ida, jtag->id); -+} -+ -+static void devm_jtag_unregister(struct device *dev, void *res) -+{ -+ jtag_unregister(*(struct jtag **)res); -+} -+ -+int devm_jtag_register(struct device *dev, struct jtag *jtag) -+{ -+ struct jtag **ptr; -+ int ret; -+ -+ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *), -+ GFP_KERNEL); -+ if (!ptr) -+ return -ENOMEM; -+ -+ ret = jtag_register(jtag); -+ if (!ret) { -+ *ptr = jtag; -+ devres_add(dev, ptr); -+ } else { -+ devres_free(ptr); -+ } -+ return ret; -+} -+EXPORT_SYMBOL_GPL(devm_jtag_register); -+ -+static void __exit jtag_exit(void) -+{ -+ ida_destroy(&jtag_ida); -+} -+ -+module_exit(jtag_exit); -+ -+MODULE_AUTHOR("Oleksandr Shamray "); -+MODULE_DESCRIPTION("Generic jtag support"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig ---- a/drivers/mailbox/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/mailbox/Kconfig 2025-12-23 10:16:09.399229222 +0000 -@@ -295,4 +295,12 @@ - acts as an interrupt controller for receiving interrupts from clients. - Say Y here if you want to build this driver. - -+config AST2700_MBOX -+ tristate "ASPEED AST2700 IPC driver" -+ depends on ARCH_ASPEED -+ help -+ Say y here to enable support for the AST2700 IPC mailbox driver, -+ providing an interface for invoking the inter-process communication -+ signals from the application processor to other masters. -+ - endif -diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile ---- a/drivers/mailbox/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/mailbox/Makefile 2025-12-23 10:16:13.555159528 +0000 -@@ -64,3 +64,5 @@ - obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o - - obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o -+ -+obj-$(CONFIG_AST2700_MBOX) += ast2700-mailbox.o diff --git a/drivers/mailbox/ast2700-mailbox.c b/drivers/mailbox/ast2700-mailbox.c --- a/drivers/mailbox/ast2700-mailbox.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/mailbox/ast2700-mailbox.c 2025-12-23 10:16:21.043034027 +0000 ++++ b/drivers/mailbox/ast2700-mailbox.c 2026-09-09 15:51:44.624239492 +0000 @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* @@ -42737,8 +43443,8 @@ diff --git a/drivers/mailbox/ast2700-mailbox.c b/drivers/mailbox/ast2700-mailbox +MODULE_DESCRIPTION("ASPEED AST2700 IPC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c ---- a/drivers/media/platform/aspeed/aspeed-video.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/media/platform/aspeed/aspeed-video.c 2025-12-23 10:16:21.131032552 +0000 +--- a/drivers/media/platform/aspeed/aspeed-video.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/media/platform/aspeed/aspeed-video.c 2026-09-09 15:51:44.727237936 +0000 @@ -4,6 +4,7 @@ #include @@ -42971,15 +43677,15 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo static const struct aspeed_video_config ast2600_config = { + .version = 6, -+ .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, -+ .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, + .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, + .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, + .compare_only = AST2600_VE_CTRL_EN_COMPARE_ONLY, +}; + +static const struct aspeed_video_config ast2700_config = { + .version = 7, - .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, - .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, ++ .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, ++ .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, + .compare_only = AST2600_VE_CTRL_EN_COMPARE_ONLY, }; @@ -42998,7 +43704,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo static bool aspeed_video_alloc_buf(struct aspeed_video *video, struct aspeed_video_addr *addr, -@@ -495,6 +596,22 @@ +@@ -495,6 +596,54 @@ static void aspeed_video_free_buf(struct aspeed_video *video, struct aspeed_video_addr *addr); @@ -43017,11 +43723,43 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + return addr; +#endif +} ++ ++static void aspeed_video_support_vga_ctrl(struct aspeed_video *v, bool yes) ++{ ++ u32 val = yes ? BIT(0) : 0; ++ u32 reg; ++ ++ if (!v || v->version < 6) ++ return; ++ ++ if (v->version == 7) ++ reg = (v->id == 1) ? 0x914 : 0x904; ++ else ++ reg = 0x104; ++ ++ regmap_update_bits(v->scu, reg, BIT(0), val); ++} ++ ++static void aspeed_video_set_vga_on(struct aspeed_video *v, bool on) ++{ ++ u32 val = on ? BIT(1) : 0; ++ u32 reg; ++ ++ if (!v || v->version < 6) ++ return; ++ ++ if (v->version == 7) ++ reg = (v->id == 1) ? 0x914 : 0x904; ++ else ++ reg = 0x104; ++ ++ regmap_update_bits(v->scu, reg, BIT(1), val); ++} + static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420) { int i; -@@ -576,13 +693,58 @@ +@@ -576,13 +725,58 @@ p->duration); } @@ -43081,7 +43819,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo if (video->v4l2_input_status) { v4l2_dbg(1, debug, &video->v4l2_dev, "No signal; don't start frame\n"); -@@ -595,18 +757,14 @@ +@@ -595,18 +789,14 @@ return -EBUSY; } @@ -43108,7 +43846,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } spin_lock_irqsave(&video->lock, flags); -@@ -624,15 +782,26 @@ +@@ -624,15 +814,26 @@ aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); aspeed_video_write(video, VE_COMP_OFFSET, 0); @@ -43140,7 +43878,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo return 0; } -@@ -660,6 +829,9 @@ +@@ -660,6 +861,9 @@ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); @@ -43150,7 +43888,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo /* Turn off the relevant clocks */ clk_disable(video->eclk); clk_disable(video->vclk); -@@ -676,7 +848,68 @@ +@@ -676,7 +880,68 @@ clk_enable(video->vclk); clk_enable(video->eclk); @@ -43219,7 +43957,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } static void aspeed_video_bufs_done(struct aspeed_video *video, -@@ -684,11 +917,18 @@ +@@ -684,11 +949,18 @@ { unsigned long flags; struct aspeed_video_buffer *buf; @@ -43238,7 +43976,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo spin_unlock_irqrestore(&video->lock, flags); } -@@ -701,12 +941,96 @@ +@@ -701,12 +973,96 @@ video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; @@ -43336,7 +44074,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo static void aspeed_video_swap_src_buf(struct aspeed_video *v) { if (v->format == VIDEO_FMT_STANDARD) -@@ -716,24 +1040,100 @@ +@@ -716,24 +1072,100 @@ if (IS_ALIGNED(v->sequence, 8)) memset((u8 *)v->bcd.virt, 0x00, VE_BCD_BUFF_SIZE); @@ -43354,9 +44092,9 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo - aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[1].dma); + aspeed_video_write(v, VE_SRC0_ADDR, _make_addr(v->srcs[0].dma)); + aspeed_video_write(v, VE_SRC1_ADDR, _make_addr(v->srcs[1].dma)); - } - } - ++ } ++} ++ +static void aspeed_video_frame_done_handler(struct aspeed_video *video, + bool buf_done) +{ @@ -43403,7 +44141,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + list_add_tail(&box->link, &video->boxes); + } + } -+ } + } + spin_unlock(&video->lock); + + aspeed_video_swap_src_buf(video); @@ -43429,8 +44167,8 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + aspeed_video_start_frame(v); + + return IRQ_HANDLED; -+} -+ + } + static irqreturn_t aspeed_video_irq(int irq, void *arg) { struct aspeed_video *video = arg; @@ -43445,7 +44183,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo sts &= aspeed_video_read(video, VE_INTERRUPT_CTRL); v4l2_dbg(2, debug, &video->v4l2_dev, "irq sts=%#x %s%s%s%s\n", sts, -@@ -755,8 +1155,6 @@ +@@ -755,8 +1187,6 @@ if (test_bit(VIDEO_RES_DETECT, &video->flags)) { aspeed_video_update(video, VE_INTERRUPT_CTRL, VE_INTERRUPT_MODE_DETECT, 0); @@ -43454,7 +44192,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo sts &= ~VE_INTERRUPT_MODE_DETECT; set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); wake_up_interruptible_all(&video->wait); -@@ -772,41 +1170,13 @@ +@@ -772,41 +1202,13 @@ } if (sts & VE_INTERRUPT_COMP_COMPLETE) { @@ -43502,7 +44240,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_TRIG_CAPTURE | -@@ -814,17 +1184,60 @@ +@@ -814,17 +1216,60 @@ VE_SEQ_CTRL_TRIG_COMP, 0); aspeed_video_update(video, VE_INTERRUPT_CTRL, VE_INTERRUPT_COMP_COMPLETE, 0); @@ -43518,12 +44256,12 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + get_box = true; + } + } ++ ++ return get_box ? IRQ_WAKE_THREAD : IRQ_HANDLED; ++} - if (test_bit(VIDEO_STREAMING, &video->flags) && !empty) - aspeed_video_start_frame(video); -+ return get_box ? IRQ_WAKE_THREAD : IRQ_HANDLED; -+} -+ +static irqreturn_t aspeed_video_md_irq(int irq, void *arg) +{ + struct aspeed_video *video = arg; @@ -43569,7 +44307,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) -@@ -896,7 +1309,7 @@ +@@ -896,7 +1341,7 @@ /* * Get the minimum HW-supported compression buffer size for the frame size. @@ -43578,7 +44316,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo * plenty even for maximum quality; any worse and the engine will simply return * incomplete JPEGs. */ -@@ -908,7 +1321,7 @@ +@@ -908,7 +1353,7 @@ unsigned int size; const unsigned int num_compression_packets = 4; const unsigned int compression_packet_size = 1024; @@ -43587,7 +44325,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo video->max_compressed_size = UINT_MAX; -@@ -929,6 +1342,7 @@ +@@ -929,6 +1374,7 @@ aspeed_video_write(video, VE_STREAM_BUF_SIZE, compression_buffer_size_reg); @@ -43595,7 +44333,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo v4l2_dbg(1, debug, &video->v4l2_dev, "Max compressed size: %#x\n", video->max_compressed_size); } -@@ -1026,9 +1440,23 @@ +@@ -1026,9 +1472,23 @@ } } @@ -43620,7 +44358,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo { bool invalid_resolution = true; int rc; -@@ -1036,7 +1464,6 @@ +@@ -1036,7 +1496,6 @@ u32 mds; u32 src_lr_edge; u32 src_tb_edge; @@ -43628,7 +44366,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo det->width = MIN_WIDTH; det->height = MIN_HEIGHT; -@@ -1107,20 +1534,51 @@ +@@ -1107,20 +1566,51 @@ return; } @@ -43686,15 +44424,16 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n", det->width, det->height); -@@ -1130,6 +1588,7 @@ +@@ -1130,6 +1620,8 @@ { struct v4l2_bt_timings *act = &video->active_timings; unsigned int size = act->width * ALIGN(act->height, 8); -+ bool is_sync_mode_ok = (video->version != 7); ++ bool is_sync_mode_ok = (video->version != 7) || ++ (video->version == 7 && video->id == 0); /* Set capture/compression frame sizes */ aspeed_video_calc_compressed_size(video, size); -@@ -1156,7 +1615,8 @@ +@@ -1156,7 +1648,8 @@ aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); /* Don't use direct mode below 1024 x 768 (irqs don't fire) */ @@ -43704,7 +44443,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode\n"); aspeed_video_write(video, VE_TGS_0, FIELD_PREP(VE_TGS_FIRST, -@@ -1170,41 +1630,50 @@ +@@ -1170,41 +1663,50 @@ aspeed_video_update(video, VE_CTRL, VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, VE_CTRL_INT_DE); @@ -43732,8 +44471,9 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo aspeed_video_update(video, VE_CTRL, VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, - VE_CTRL_DIRECT_FETCH); -- } -- ++ ctrl); + } + - size *= 4; - - if (size != video->srcs[0].size) { @@ -43753,9 +44493,8 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo - &video->srcs[1].dma, video->srcs[1].size); - aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); - aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); -+ ctrl); - } - +- } +- - return; + aspeed_video_write(video, VE_SRC0_ADDR, _make_addr(video->srcs[0].dma)); + aspeed_video_write(video, VE_SRC1_ADDR, _make_addr(video->srcs[1].dma)); @@ -43782,7 +44521,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } static void aspeed_video_update_regs(struct aspeed_video *video) -@@ -1219,6 +1688,8 @@ +@@ -1219,6 +1721,8 @@ u32 ctrl = 0; u32 seq_ctrl = 0; @@ -43791,7 +44530,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n", video->frame_rate); v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n", -@@ -1234,14 +1705,26 @@ +@@ -1234,14 +1738,35 @@ else aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0); @@ -43800,6 +44539,15 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + + if (video->input == VIDEO_INPUT_DVI) + ctrl |= VE_CTRL_SOURCE; ++ ++ if (video->version == 7) { ++ if (video->input == VIDEO_INPUT_DVI) ++ ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_CRT2); ++ else if (video->input == VIDEO_INPUT_VGA && video->id == 0) ++ ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_D1); ++ else ++ ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_48MHz); ++ } + if (video->frame_rate) ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); @@ -43818,18 +44566,18 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo if (video->yuv420) seq_ctrl |= VE_SEQ_CTRL_YUV420; -@@ -1252,7 +1735,9 @@ +@@ -1252,7 +1777,9 @@ aspeed_video_update(video, VE_SEQ_CTRL, video->jpeg_mode | VE_SEQ_CTRL_YUV420, seq_ctrl); - aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, ctrl); + aspeed_video_update(video, VE_CTRL, + VE_CTRL_FRC | VE_CTRL_AUTO_OR_CURSOR | -+ VE_CTRL_SOURCE, ctrl); ++ VE_CTRL_SOURCE | VE_CTRL_CLK_DELAY, ctrl); aspeed_video_update(video, VE_COMP_CTRL, VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR | VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM | -@@ -1278,8 +1763,16 @@ +@@ -1278,8 +1805,18 @@ aspeed_video_write(video, VE_COMP_OFFSET, 0); aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); @@ -43840,13 +44588,24 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + if (video->version == 7) { + if (video->input == VIDEO_INPUT_DVI) + ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_CRT2); ++ else if (video->input == VIDEO_INPUT_VGA && video->id == 0) ++ ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_D1); + else + ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_48MHz); + } aspeed_video_write(video, VE_CTRL, ctrl); aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD); -@@ -1311,12 +1804,7 @@ +@@ -1303,6 +1840,8 @@ + + static void aspeed_video_start(struct aspeed_video *video) + { ++ aspeed_video_set_vga_on(video, true); ++ + aspeed_video_on(video); + + aspeed_video_init_regs(video); +@@ -1311,30 +1850,18 @@ aspeed_video_get_resolution(video); /* Set timings since the device is being opened for the first time */ @@ -43860,7 +44619,11 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } static void aspeed_video_stop(struct aspeed_video *video) -@@ -1326,15 +1814,6 @@ + { ++ aspeed_video_set_vga_on(video, false); ++ + set_bit(VIDEO_STOPPED, &video->flags); + cancel_delayed_work_sync(&video->res_work); aspeed_video_off(video); @@ -43876,7 +44639,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; video->flags = 0; } -@@ -1342,10 +1821,14 @@ +@@ -1342,10 +1869,14 @@ static int aspeed_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { @@ -43891,7 +44654,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo return 0; } -@@ -1383,7 +1866,8 @@ +@@ -1383,7 +1914,8 @@ switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_JPEG: @@ -43901,7 +44664,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo break; case V4L2_PIX_FMT_AJPG: video->format = VIDEO_FMT_ASPEED; -@@ -1401,10 +1885,10 @@ +@@ -1401,10 +1933,10 @@ { struct aspeed_video *video = video_drvdata(file); @@ -43914,7 +44677,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo inp->type = V4L2_INPUT_TYPE_CAMERA; inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; inp->status = video->v4l2_input_status; -@@ -1414,15 +1898,116 @@ +@@ -1414,15 +1946,110 @@ static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) { @@ -43934,20 +44697,14 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo + if (i >= VIDEO_INPUT_MAX) + return -EINVAL; + -+ if (i == video->input) -+ return 0; -+ -+ if (vb2_is_busy(&video->queue)) -+ return -EBUSY; -+ + if (IS_ERR(video->scu)) { + v4l2_dbg(1, debug, &video->v4l2_dev, "%s: scu isn't ready for input-control\n", __func__); - return -EINVAL; ++ return -EINVAL; + } + + if (IS_ERR(video->gfx) && i == VIDEO_INPUT_GFX) { + v4l2_dbg(1, debug, &video->v4l2_dev, "%s: gfx isn't ready for GFX input\n", __func__); -+ return -EINVAL; + return -EINVAL; + } + + // prepare memory space for user to put test batch @@ -44033,7 +44790,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo return 0; } -@@ -1520,6 +2105,12 @@ +@@ -1520,6 +2147,12 @@ { struct aspeed_video *video = video_drvdata(file); @@ -44046,7 +44803,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo if (timings->bt.width == video->active_timings.width && timings->bt.height == video->active_timings.height) return 0; -@@ -1527,13 +2118,7 @@ +@@ -1527,13 +2160,7 @@ if (vb2_is_busy(&video->queue)) return -EBUSY; @@ -44061,7 +44818,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo timings->type = V4L2_DV_BT_656_1120; -@@ -1589,6 +2174,37 @@ +@@ -1589,6 +2216,37 @@ NULL, NULL); } @@ -44099,7 +44856,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo static int aspeed_video_dv_timings_cap(struct file *file, void *fh, struct v4l2_dv_timings_cap *cap) { -@@ -1641,6 +2257,8 @@ +@@ -1641,6 +2299,8 @@ .vidioc_enum_dv_timings = aspeed_video_enum_dv_timings, .vidioc_dv_timings_cap = aspeed_video_dv_timings_cap, @@ -44108,7 +44865,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo .vidioc_subscribe_event = aspeed_video_sub_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -@@ -1710,6 +2328,9 @@ +@@ -1710,6 +2370,9 @@ struct delayed_work *dwork = to_delayed_work(work); struct aspeed_video *video = container_of(dwork, struct aspeed_video, res_work); @@ -44118,7 +44875,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo aspeed_video_on(video); -@@ -1723,8 +2344,14 @@ +@@ -1723,8 +2386,14 @@ aspeed_video_get_resolution(video); @@ -44135,7 +44892,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo static const struct v4l2_event ev = { .type = V4L2_EVENT_SOURCE_CHANGE, .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, -@@ -1740,6 +2367,32 @@ +@@ -1740,6 +2409,32 @@ done: clear_bit(VIDEO_RES_CHANGE, &video->flags); wake_up_interruptible_all(&video->wait); @@ -44168,7 +44925,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } static int aspeed_video_open(struct file *file) -@@ -1785,7 +2438,7 @@ +@@ -1785,7 +2480,7 @@ .read = vb2_fop_read, .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, @@ -44177,7 +44934,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo .open = aspeed_video_open, .release = aspeed_video_release, }; -@@ -1830,13 +2483,17 @@ +@@ -1830,13 +2525,17 @@ video->sequence = 0; video->perf.duration_max = 0; video->perf.duration_min = 0xffffffff; @@ -44199,7 +44956,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } set_bit(VIDEO_STREAMING, &video->flags); -@@ -1860,8 +2517,7 @@ +@@ -1860,8 +2559,7 @@ * Need to force stop any DMA and try and get HW into a good * state for future calls to start streaming again. */ @@ -44209,7 +44966,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo aspeed_video_init_regs(video); -@@ -1885,7 +2541,8 @@ +@@ -1885,7 +2583,8 @@ spin_unlock_irqrestore(&video->lock, flags); if (test_bit(VIDEO_STREAMING, &video->flags) && @@ -44219,7 +44976,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo aspeed_video_start_frame(video); } -@@ -1911,6 +2568,7 @@ +@@ -1911,6 +2610,7 @@ val08 = aspeed_video_read(v, VE_CTRL); if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) { seq_printf(s, " %-20s:\tDirect fetch\n", "Mode"); @@ -44227,7 +44984,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode", FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32"); } else { -@@ -1962,19 +2620,19 @@ +@@ -1962,19 +2662,19 @@ } DEFINE_SHOW_ATTRIBUTE(aspeed_video_debugfs); @@ -44254,7 +45011,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo } #else static void aspeed_video_debugfs_remove(struct aspeed_video *video) { } -@@ -2028,6 +2686,8 @@ +@@ -2028,6 +2728,8 @@ vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; vbq->dev = v4l2_dev->dev; @@ -44263,7 +45020,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo vbq->lock = &video->video_lock; vbq->ops = &aspeed_video_vb2_ops; vbq->mem_ops = &vb2_dma_contig_memops; -@@ -2070,11 +2730,30 @@ +@@ -2070,11 +2772,30 @@ return 0; } @@ -44294,7 +45051,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) { -@@ -2082,14 +2761,36 @@ +@@ -2082,14 +2803,36 @@ return -ENODEV; } @@ -44333,7 +45090,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo video->eclk = devm_clk_get(dev, "eclk"); if (IS_ERR(video->eclk)) { dev_err(dev, "Unable to get ECLK\n"); -@@ -2111,22 +2812,53 @@ +@@ -2111,22 +2854,53 @@ if (rc) goto err_unprepare_eclk; @@ -44393,7 +45150,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); -@@ -2134,6 +2866,9 @@ +@@ -2134,6 +2908,9 @@ err_release_reserved_mem: of_reserved_mem_device_release(dev); @@ -44403,7 +45160,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo clk_unprepare(video->vclk); err_unprepare_eclk: clk_unprepare(video->eclk); -@@ -2145,6 +2880,7 @@ +@@ -2145,6 +2922,7 @@ { .compatible = "aspeed,ast2400-video-engine", .data = &ast2400_config }, { .compatible = "aspeed,ast2500-video-engine", .data = &ast2500_config }, { .compatible = "aspeed,ast2600-video-engine", .data = &ast2600_config }, @@ -44411,7 +45168,13 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo {} }; MODULE_DEVICE_TABLE(of, aspeed_video_of_match); -@@ -2159,6 +2895,10 @@ +@@ -2154,11 +2932,16 @@ + const struct aspeed_video_config *config; + struct aspeed_video *video; + int rc; ++ bool vga_ctrl; + + video = devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL); if (!video) return -ENOMEM; @@ -44422,7 +45185,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo video->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(video->base)) return PTR_ERR(video->base); -@@ -2167,8 +2907,10 @@ +@@ -2167,8 +2950,10 @@ if (!config) return -ENODEV; @@ -44433,7 +45196,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo video->frame_rate = 30; video->jpeg_hq_quality = 1; -@@ -2178,6 +2920,19 @@ +@@ -2178,14 +2963,31 @@ init_waitqueue_head(&video->wait); INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); INIT_LIST_HEAD(&video->buffers); @@ -44453,15 +45216,20 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo rc = aspeed_video_init(video); if (rc) -@@ -2185,7 +2940,6 @@ + return rc; ++ /* vga_ctrl is a property to say if VGA will be on/off with KVM */ ++ vga_ctrl = of_find_property(pdev->dev.of_node, "vga_ctrl", NULL) ? 1 : 0; ++ aspeed_video_support_vga_ctrl(video, vga_ctrl); ++ aspeed_video_set_vga_on(video, false); ++ rc = aspeed_video_setup_video(video); if (rc) { - aspeed_video_free_buf(video, &video->jpeg); clk_unprepare(video->vclk); clk_unprepare(video->eclk); return rc; -@@ -2193,6 +2947,9 @@ +@@ -2193,6 +2995,9 @@ aspeed_video_debugfs_create(video); @@ -44471,7 +45239,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo return 0; } -@@ -2204,8 +2961,12 @@ +@@ -2204,8 +3009,12 @@ aspeed_video_off(video); @@ -44484,7 +45252,7 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo clk_unprepare(video->vclk); clk_unprepare(video->eclk); -@@ -2215,7 +2976,7 @@ +@@ -2215,7 +3024,7 @@ v4l2_device_unregister(v4l2_dev); @@ -44494,8 +45262,8 @@ diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platfo of_reserved_mem_device_release(dev); } diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c ---- a/drivers/mmc/host/sdhci-of-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/mmc/host/sdhci-of-aspeed.c 2025-12-23 10:16:20.668040312 +0000 +--- a/drivers/mmc/host/sdhci-of-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/mmc/host/sdhci-of-aspeed.c 2026-09-09 15:51:44.134246896 +0000 @@ -11,8 +11,10 @@ #include #include @@ -44516,12 +45284,13 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe #define ASPEED_SDC_S1_PHASE_OUT GENMASK(15, 11) #define ASPEED_SDC_S1_PHASE_IN_EN BIT(10) #define ASPEED_SDC_S1_PHASE_OUT_EN GENMASK(9, 8) -@@ -31,61 +35,52 @@ +@@ -31,61 +35,53 @@ #define ASPEED_SDC_S0_PHASE_OUT_EN GENMASK(1, 0) #define ASPEED_SDC_PHASE_MAX 31 +#define ASPEED_SDHCI_TAP_PARAM_INVERT_CLK BIT(4) +#define ASPEED_SDHCI_NR_TAPS 15 ++#define ASPEED_SDHCI_MAX_SWEEPS 10 + /* SDIO{10,20} */ -#define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26) @@ -44597,7 +45366,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe * 1 | CAP2_SDR104 | SDIO244 | SDIO24 */ static void aspeed_sdc_set_slot_capability(struct sdhci_host *host, struct aspeed_sdc *sdc, -@@ -125,222 +120,217 @@ +@@ -125,222 +121,307 @@ spin_unlock(&sdc->lock); } @@ -44724,38 +45493,89 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe + pltfm_priv = sdhci_priv(host); + aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv); + aspeed_sdc = aspeed_sdhci->parent; - -- taps->in = aspeed_sdhci_phase_to_tap(dev, rate, phases->in_deg); -- taps->out = aspeed_sdhci_phase_to_tap(dev, rate, phases->out_deg); --} ++ + if (!IS_ERR(aspeed_sdc->rst)) { + for (i = 0; i < ARRAY_SIZE(reg_array); i++) + save_array[i] = sdhci_readl(host, reg_array[i]); ++ ++ tran_mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); ++ mmc8_mode = readl(aspeed_sdc->regs); ++ ++ reset_control_assert(aspeed_sdc->rst); ++ mdelay(1); ++ reset_control_deassert(aspeed_sdc->rst); ++ mdelay(1); ++ ++ for (i = 0; i < ARRAY_SIZE(reg_array); i++) ++ sdhci_writel(host, save_array[i], reg_array[i]); ++ ++ sdhci_writew(host, tran_mode, SDHCI_TRANSFER_MODE); ++ writel(mmc8_mode, aspeed_sdc->regs); + +- taps->in = aspeed_sdhci_phase_to_tap(dev, rate, phases->in_deg); +- taps->out = aspeed_sdhci_phase_to_tap(dev, rate, phases->out_deg); ++ sdhci_set_clock(host, host->clock); ++ } ++ ++ sdhci_reset(host, mask); + } -static void -aspeed_sdhci_configure_phase(struct sdhci_host *host, unsigned long rate) --{ ++/* ++ * aspeed_sdhci_find_center_tap - find the midpoint of the widest passing window ++ * @pass: boolean array [0..total-1], true = tuning passed at this position ++ * @total: number of phase positions (ASPEED_SDHCI_NR_TAPS * 2 = 30) ++ * ++ * Phase space layout (15 taps = half cycle at 200 MHz, ~167 ps/tap): ++ * pos [0..14] - rising edge, tap delay 0..14 ( 0° .. ~168°) ++ * pos [15..29] - falling edge, tap delay 0..14 (180° .. ~348°) ++ * ++ * The array is treated as circular so windows that wrap across the ++ * rising/falling boundary (around 0°/360°) are detected correctly. ++ * ++ * Returns a 5-bit phase_bits value: ++ * bits [3:0] = tap index ++ * bit [4] = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK (set for falling edge) ++ */ ++static u32 aspeed_sdhci_find_center_tap(const bool *pass, int total) + { - struct aspeed_sdhci_tap_param _taps = {0}, *taps = &_taps; - struct mmc_clk_phase *params; - struct aspeed_sdhci *sdhci; - struct device *dev; -+ tran_mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); -+ mmc8_mode = readl(aspeed_sdc->regs); ++ int pos, cur_start = -1, cur_len = 0, best_start = 0, best_len = 0; ++ int center_pos; - dev = mmc_dev(host->mmc); - sdhci = sdhci_pltfm_priv(sdhci_priv(host)); -+ reset_control_assert(aspeed_sdc->rst); -+ mdelay(1); -+ reset_control_deassert(aspeed_sdc->rst); -+ mdelay(1); ++ /* ++ * Double-scan the circular buffer: the second pass detects windows ++ * that straddle the index-0 wrap-around boundary. The window length ++ * is capped at 'total' so a full-circle window is counted only once. ++ */ ++ for (pos = 0; pos < total * 2; pos++) { ++ if (pass[pos % total]) { ++ if (cur_start < 0) ++ cur_start = pos; ++ if (++cur_len > total) ++ cur_len = total; ++ if (cur_len > best_len) { ++ best_len = cur_len; ++ best_start = cur_start; ++ } ++ } else { ++ cur_start = -1; ++ cur_len = 0; ++ } ++ } - if (!sdhci->phase_desc) - return; -+ for (i = 0; i < ARRAY_SIZE(reg_array); i++) -+ sdhci_writel(host, save_array[i], reg_array[i]); ++ if (!best_len) ++ return 0; + -+ sdhci_writew(host, tran_mode, SDHCI_TRANSFER_MODE); -+ writel(mmc8_mode, aspeed_sdc->regs); ++ center_pos = (best_start + best_len / 2) % total; - params = &sdhci->phase_map.phase[host->timing]; - aspeed_sdhci_phases_to_taps(dev, rate, params, taps); @@ -44765,10 +45585,10 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe - taps->in & ASPEED_SDHCI_NR_TAPS, - taps->out & ASPEED_SDHCI_NR_TAPS, - params->in_deg, params->out_deg, rate, host->timing); -+ sdhci_set_clock(host, host->clock); -+ } ++ if (center_pos < ASPEED_SDHCI_NR_TAPS) ++ return (u32)center_pos; + -+ sdhci_reset(host, mask); ++ return (u32)(center_pos - ASPEED_SDHCI_NR_TAPS) | ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; } -static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) @@ -44780,32 +45600,74 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe struct aspeed_sdhci *sdhci; - int div; - u16 clk; -- -- pltfm_host = sdhci_priv(host); -- sdhci = sdhci_pltfm_priv(pltfm_host); + struct aspeed_sdc *sdc; + struct device *dev; ++ /* ++ * 15 taps cover half a 200 MHz clock cycle (2.5 ns ≈ 167 ps/tap). ++ * Rising and falling edges together span a full cycle: 30 positions. ++ */ ++ const int total = ASPEED_SDHCI_NR_TAPS * 2; ++ bool pass[ASPEED_SDHCI_NR_TAPS * 2]; ++ u32 enable_mask, base, val, phase_bits; ++ int pos, pass_count, sweep; -- parent = clk_get_rate(pltfm_host->clk); -+ u32 val, left, right, edge; -+ u32 window, oldwindow = 0, center; -+ u32 in_phase, out_phase, enable_mask, inverted = 0; - -- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); +- pltfm_host = sdhci_priv(host); +- sdhci = sdhci_pltfm_priv(pltfm_host); + dev = mmc_dev(host->mmc); + pltfm_priv = sdhci_priv(host); + sdhci = sdhci_pltfm_priv(pltfm_priv); + sdc = sdhci->parent; +- parent = clk_get_rate(pltfm_host->clk); ++ enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN | ASPEED_SDC_S0_PHASE_IN_EN; ++ base = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; + +- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); ++ /* ++ * For each phase direction (input then output), sweep all 30 ++ * positions. If every position passes, the result is ++ * untrustworthy — all phases are not really reliable but we ++ * cannot detect where the unreliable ones are. Re-run the ++ * sweep up to ASPEED_SDHCI_MAX_SWEEPS times, skipping ++ * already-failed taps, until some fail and reveal the true ++ * window. ++ */ + - if (clock == 0) - return; -+ out_phase = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; ++ /* -------- Step 1: scan all input-phase positions -------- */ ++ for (pos = 0; pos < total; pos++) ++ pass[pos] = true; ++ ++ for (sweep = 0; sweep < ASPEED_SDHCI_MAX_SWEEPS; sweep++) { ++ for (pos = 0; pos < total; pos++) { ++ if (!pass[pos]) ++ continue; ++ ++ phase_bits = (pos < ASPEED_SDHCI_NR_TAPS) ++ ? (u32)pos ++ : (u32)(pos - ASPEED_SDHCI_NR_TAPS) | ++ ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; ++ ++ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_IN_SHIFT); ++ writel(val, sdc->regs + ASPEED_SDC_PHASE); ++ ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) ++ pass[pos] = false; ++ ++ dev_dbg(dev, "in pos=%2d (%s tap%2u) %s\n", pos, ++ pos < ASPEED_SDHCI_NR_TAPS ? "rise" : "fall", ++ pos % ASPEED_SDHCI_NR_TAPS, ++ pass[pos] ? "pass" : "fail"); ++ } - if (WARN_ON(clock > host->max_clk)) - clock = host->max_clk; -+ enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN | ASPEED_SDC_S0_PHASE_IN_EN; ++ for (pos = 0, pass_count = 0; pos < total; pos++) ++ if (pass[pos]) ++ pass_count++; - /* +- /* - * Regarding the AST2600: - * - * If (EMMC12C[7:6], EMMC12C[15:8] == 0) then @@ -44820,103 +45682,106 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe - * Keep the one-hot behaviour for backwards compatibility except for - * supporting the value 0 in (EMMC12C[7:6], EMMC12C[15:8]), and capture - * the 0-value capability in clk_div_start. -+ * There are two window upon clock rising and falling edge. -+ * Iterate each tap delay to find the valid window and choose the -+ * bigger one, set the tap delay at the middle of window. - */ +- */ - for (div = sdhci->pdata->clk_div_start; div < 256; div *= 2) { - bus = parent / div; - if (bus <= clock) -- break; -+ for (edge = 0; edge < 2; edge++) { -+ if (edge == 1) -+ inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; ++ dev_dbg(dev, "input phase: sweep %d, %d/%d passed\n", ++ sweep, pass_count, total); + -+ val = (out_phase | enable_mask | (inverted << ASPEED_SDC_S0_PHASE_IN_SHIFT)); ++ if (pass_count < total || !pass_count) + break; + } + +- div >>= 1; ++ if (!pass_count) ++ dev_warn(dev, "input phase: no positions passed tuning\n"); + +- clk = div << SDHCI_DIVIDER_SHIFT; ++ phase_bits = aspeed_sdhci_find_center_tap(pass, total); ++ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_IN_SHIFT); ++ writel(val, sdc->regs + ASPEED_SDC_PHASE); ++ dev_dbg(dev, "input center: phase_bits=0x%02x reg=0x%08x\n", phase_bits, val); + -+ /* find the left boundary */ -+ for (left = 0; left < ASPEED_SDHCI_NR_TAPS + 1; left++) { -+ in_phase = val | (left << ASPEED_SDC_S0_PHASE_IN_SHIFT); -+ writel(in_phase, sdc->regs + ASPEED_SDC_PHASE); ++ /* -------- Step 2: scan all output-phase positions -------- */ ++ base = val & ~ASPEED_SDC_S0_PHASE_OUT; + -+ if (!mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ } ++ for (pos = 0; pos < total; pos++) ++ pass[pos] = true; + -+ /* find the right boundary */ -+ for (right = left + 1; right < ASPEED_SDHCI_NR_TAPS + 1; right++) { -+ in_phase = val | (right << ASPEED_SDC_S0_PHASE_IN_SHIFT); -+ writel(in_phase, sdc->regs + ASPEED_SDC_PHASE); ++ for (sweep = 0; sweep < ASPEED_SDHCI_MAX_SWEEPS; sweep++) { ++ for (pos = 0; pos < total; pos++) { ++ if (!pass[pos]) ++ continue; + -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ } ++ phase_bits = (pos < ASPEED_SDHCI_NR_TAPS) ++ ? (u32)pos ++ : (u32)(pos - ASPEED_SDHCI_NR_TAPS) | ++ ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; ++ ++ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_OUT_SHIFT); ++ writel(val, sdc->regs + ASPEED_SDC_PHASE); + -+ window = right - left; -+ pr_debug("tuning window[%d][%d~%d] = %d\n", edge, left, right, window); ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) ++ pass[pos] = false; + -+ if (window > oldwindow) { -+ oldwindow = window; -+ center = (((right - 1) + left) / 2) | inverted; ++ dev_dbg(dev, "out pos=%2d (%s tap%2u) %s\n", pos, ++ pos < ASPEED_SDHCI_NR_TAPS ? "rise" : "fall", ++ pos % ASPEED_SDHCI_NR_TAPS, ++ pass[pos] ? "pass" : "fail"); + } - } - -- div >>= 1; -+ val = (out_phase | enable_mask | (center << ASPEED_SDC_S0_PHASE_IN_SHIFT)); -+ writel(val, sdc->regs + ASPEED_SDC_PHASE); - -- clk = div << SDHCI_DIVIDER_SHIFT; -+ pr_debug("input tuning result=%x\n", val); - aspeed_sdhci_configure_phase(host, bus); -+ inverted = 0; -+ out_phase = val & ~ASPEED_SDC_S0_PHASE_OUT; -+ in_phase = out_phase; -+ oldwindow = 0; ++ for (pos = 0, pass_count = 0; pos < total; pos++) ++ if (pass[pos]) ++ pass_count++; - sdhci_enable_clk(host, clk); -} -+ for (edge = 0; edge < 2; edge++) { -+ if (edge == 1) -+ inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; ++ dev_dbg(dev, "output phase: sweep %d, %d/%d passed\n", ++ sweep, pass_count, total); -static unsigned int aspeed_sdhci_get_max_clock(struct sdhci_host *host) -{ - if (host->mmc->f_max) - return host->mmc->f_max; -+ val = (in_phase | enable_mask | (inverted << ASPEED_SDC_S0_PHASE_OUT_SHIFT)); ++ if (pass_count < total || !pass_count) ++ break; ++ } ++ ++ if (!pass_count) ++ dev_warn(dev, "output phase: no positions passed tuning\n"); ++ ++ phase_bits = aspeed_sdhci_find_center_tap(pass, total); ++ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_OUT_SHIFT); ++ writel(val, sdc->regs + ASPEED_SDC_PHASE); ++ dev_dbg(dev, "output center: phase_bits=0x%02x reg=0x%08x\n", phase_bits, val); - return sdhci_pltfm_clk_get_max_clock(host); --} -+ /* find the left boundary */ -+ for (left = 0; left < ASPEED_SDHCI_NR_TAPS + 1; left++) { -+ out_phase = val | (left << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -+ writel(out_phase, sdc->regs + ASPEED_SDC_PHASE); ++ return mmc_send_tuning(host->mmc, opcode, NULL); + } -static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width) --{ -- struct sdhci_pltfm_host *pltfm_priv; ++static void aspeed_sdhci_voltage_switch(struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_priv; - struct aspeed_sdhci *aspeed_sdhci; - struct aspeed_sdc *aspeed_sdc; - u8 ctrl; -+ if (!mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ } ++ struct aspeed_sdhci *sdhci; ++ struct aspeed_sdc *sdc; ++ u32 out_phase, enable_mask, inverted = 1; -- pltfm_priv = sdhci_priv(host); + pltfm_priv = sdhci_priv(host); - aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv); - aspeed_sdc = aspeed_sdhci->parent; -+ /* find the right boundary */ -+ for (right = left + 1; right < ASPEED_SDHCI_NR_TAPS + 1; right++) { -+ out_phase = val | (right << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -+ writel(out_phase, sdc->regs + ASPEED_SDC_PHASE); ++ sdhci = sdhci_pltfm_priv(pltfm_priv); ++ sdc = sdhci->parent; - /* Set/clear 8-bit mode */ - aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci, - width == MMC_BUS_WIDTH_8); -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ } ++ enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN | ASPEED_SDC_S0_PHASE_IN_EN; - /* Set/clear 1 or 4 bit mode */ - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); @@ -44926,32 +45791,21 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe - ctrl &= ~SDHCI_CTRL_4BITBUS; - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} -+ window = right - left; -+ pr_debug("tuning window[%d][%d~%d] = %d\n", edge, left, right, window); ++ inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; ++ out_phase = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; ++ out_phase |= (inverted << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -static u32 aspeed_sdhci_readl(struct sdhci_host *host, int reg) -{ - u32 val = readl(host->ioaddr + reg); -+ if (window > oldwindow) { -+ oldwindow = window; -+ center = (((right - 1) + left) / 2) | inverted; -+ } -+ } ++ /* output inverse */ ++ writel(out_phase | enable_mask, sdc->regs + ASPEED_SDC_PHASE); - if (unlikely(reg == SDHCI_PRESENT_STATE) && - (host->mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)) - val ^= SDHCI_CARD_PRESENT; -+ val = (in_phase | enable_mask | (center << ASPEED_SDC_S0_PHASE_OUT_SHIFT)); -+ writel(val, sdc->regs + ASPEED_SDC_PHASE); - +- - return val; -+ pr_debug("output tuning result=%x\n", val); -+ -+ return mmc_send_tuning(host->mmc, opcode, NULL); -+} -+ -+static void aspeed_sdhci_voltage_switch(struct sdhci_host *host) -+{ + mdelay(30); } @@ -44977,7 +45831,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe }; static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev, -@@ -372,12 +362,6 @@ +@@ -372,12 +453,6 @@ int slot; int ret; @@ -44990,7 +45844,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev)); if (IS_ERR(host)) return PTR_ERR(host); -@@ -395,14 +379,6 @@ +@@ -395,14 +470,6 @@ else if (slot >= 2) return -EINVAL; @@ -45005,7 +45859,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe dev->width_mask = !slot ? ASPEED_SDC_S0_MMC8 : ASPEED_SDC_S1_MMC8; dev_info(&pdev->dev, "Configured for slot %d\n", slot); -@@ -413,11 +389,13 @@ +@@ -413,11 +480,13 @@ of_property_read_bool(np, "sd-uhs-sdr104")) { aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V, true, slot); @@ -45022,7 +45876,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe } pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); -@@ -434,9 +412,6 @@ +@@ -434,9 +503,6 @@ if (ret) goto err_sdhci_add; @@ -45032,7 +45886,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe ret = sdhci_add_host(host); if (ret) goto err_sdhci_add; -@@ -469,45 +444,11 @@ +@@ -469,45 +535,11 @@ .clk_div_start = 2, }; @@ -45081,7 +45935,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe { } }; MODULE_DEVICE_TABLE(of, aspeed_sdhci_of_match); -@@ -522,11 +463,22 @@ +@@ -522,11 +554,22 @@ .remove_new = aspeed_sdhci_remove, }; @@ -45104,7 +45958,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe int ret; sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL); -@@ -535,6 +487,23 @@ +@@ -535,6 +578,23 @@ spin_lock_init(&sdc->lock); @@ -45128,7 +45982,7 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe sdc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sdc->clk)) return PTR_ERR(sdc->clk); -@@ -579,15 +548,6 @@ +@@ -579,15 +639,6 @@ clk_disable_unprepare(sdc->clk); } @@ -45144,37 +45998,10 @@ diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspe static struct platform_driver aspeed_sdc_driver = { .driver = { .name = "sd-controller-aspeed", -diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig ---- a/drivers/net/can/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/net/can/Kconfig 2025-12-23 10:16:08.679241296 +0000 -@@ -66,6 +66,12 @@ - - if CAN_NETLINK - -+config CAN_ASPEED -+ tristate "ASPEED CAN" -+ depends on ARM64 || COMPILE_TEST -+ help -+ ASPEED CAN driver. -+ - config CAN_CALC_BITTIMING - bool "CAN bit-timing calculation" - default y -diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile ---- a/drivers/net/can/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/net/can/Makefile 2025-12-23 10:16:12.642174838 +0000 -@@ -15,6 +15,7 @@ - obj-y += usb/ - obj-y += softing/ - -+obj-$(CONFIG_CAN_ASPEED) += aspeed_can.o - obj-$(CONFIG_CAN_AT91) += at91_can.o - obj-$(CONFIG_CAN_BXCAN) += bxcan.o - obj-$(CONFIG_CAN_CAN327) += can327.o diff --git a/drivers/net/can/aspeed_can.c b/drivers/net/can/aspeed_can.c --- a/drivers/net/can/aspeed_can.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/can/aspeed_can.c 2025-12-23 10:16:20.944035686 +0000 -@@ -0,0 +1,1720 @@ ++++ b/drivers/net/can/aspeed_can.c 2026-09-09 15:51:44.506241275 +0000 +@@ -0,0 +1,1728 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* ASPEED CAN device driver + * @@ -45784,6 +46611,14 @@ diff --git a/drivers/net/can/aspeed_can.c b/drivers/net/can/aspeed_can.c + + for (i = 0; i < 0x50; i += 4) + netdev_info(ndev, "REG(%03x): 0x%08x\n", i, readl(priv->reg_base + i)); ++ ++ netdev_info(ndev, "TX_MIRROR\n"); ++ for (i = 0; i < 0x30; i += 4) ++ netdev_info(ndev, "(0x%02x): 0x%08x\n", i, readl(priv->reg_base + CAN_TBUF_MIRROR + i)); ++ ++ netdev_info(ndev, "RX_BUF\n"); ++ for (i = 0; i < 0x30; i += 4) ++ netdev_info(ndev, "(0x%02x): 0x%08x\n", i, readl(priv->reg_base + CAN_RBUF + i)); +} + +static int aspeed_can_set_bittiming(struct net_device *ndev) @@ -46895,813 +47730,29 @@ diff --git a/drivers/net/can/aspeed_can.c b/drivers/net/can/aspeed_can.c +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chin-Ting Kuo "); +MODULE_DESCRIPTION("ASPEED CAN interface"); -diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig ---- a/drivers/net/ethernet/faraday/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/net/ethernet/faraday/Kconfig 2025-12-23 10:16:21.145032318 +0000 -@@ -6,7 +6,7 @@ - config NET_VENDOR_FARADAY - bool "Faraday devices" - default y -- depends on ARM || COMPILE_TEST -+ depends on ARM || ARM64 || COMPILE_TEST - help - If you have a network (Ethernet) card belonging to this class, say Y. - -@@ -28,11 +28,10 @@ - - config FTGMAC100 - tristate "Faraday FTGMAC100 Gigabit Ethernet support" -- depends on ARM || COMPILE_TEST -- depends on !64BIT || BROKEN -+ depends on ARM || ARM64 || COMPILE_TEST - select PHYLIB - select FIXED_PHY -- select MDIO_ASPEED if MACH_ASPEED_G6 -+ select MDIO_ASPEED if ARCH_ASPEED - select CRC32 - help - This driver supports the FTGMAC100 Gigabit Ethernet controller -diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c ---- a/drivers/net/ethernet/faraday/ftgmac100.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/net/ethernet/faraday/ftgmac100.c 2025-12-23 10:16:21.145032318 +0000 -@@ -9,6 +9,7 @@ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - - #include -+#include - #include - #include - #include -@@ -19,6 +20,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -98,6 +100,7 @@ - struct work_struct reset_task; - struct mii_bus *mii_bus; - struct clk *clk; -+ struct reset_control *rst; - - /* AST2500/AST2600 RMII ref clock gate */ - struct clk *rclk; -@@ -119,6 +122,9 @@ - /* Misc */ - bool need_mac_restart; - bool is_aspeed; -+ -+ /* AST2700 SGMII */ -+ struct phy *sgmii; - }; - - static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr) -@@ -148,6 +154,23 @@ - { - u32 maccr = 0; - -+ /* RMII needs SCU reset to clear status */ -+ if (priv->netdev->phydev->interface == PHY_INTERFACE_MODE_RMII) { -+ int err; -+ -+ err = reset_control_assert(priv->rst); -+ if (err) { -+ dev_err(priv->dev, "Failed to reset mac (%d)\n", err); -+ return err; -+ } -+ usleep_range(10000, 20000); -+ err = reset_control_deassert(priv->rst); -+ if (err) { -+ dev_err(priv->dev, "Failed to deassert mac reset (%d)\n", err); -+ return err; -+ } -+ } -+ - switch (priv->cur_speed) { - case SPEED_10: - case 0: /* no link */ -@@ -265,10 +288,12 @@ - iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR); - - /* Setup RX ring buffer base */ -- iowrite32(priv->rxdes_dma, priv->base + FTGMAC100_OFFSET_RXR_BADR); -+ iowrite32(lower_32_bits(priv->rxdes_dma), priv->base + FTGMAC100_OFFSET_RXR_BADR); -+ iowrite32(upper_32_bits(priv->rxdes_dma), priv->base + FTGMAC100_OFFSET_RXR_BADDR_HIGH); - - /* Setup TX ring buffer base */ -- iowrite32(priv->txdes_dma, priv->base + FTGMAC100_OFFSET_NPTXR_BADR); -+ iowrite32(lower_32_bits(priv->txdes_dma), priv->base + FTGMAC100_OFFSET_NPTXR_BADR); -+ iowrite32(upper_32_bits(priv->txdes_dma), priv->base + FTGMAC100_OFFSET_TXR_BADDR_HIGH); - - /* Configure RX buffer size */ - iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE), -@@ -321,6 +346,7 @@ - static void ftgmac100_start_hw(struct ftgmac100 *priv) - { - u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR); -+ struct phy_device *phydev = priv->netdev->phydev; - - /* Keep the original GMAC and FAST bits */ - maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE); -@@ -349,6 +375,10 @@ - if (priv->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) - maccr |= FTGMAC100_MACCR_RM_VLAN; - -+ if (of_device_is_compatible(priv->dev->of_node, "aspeed,ast2700-mac") && -+ phydev && phydev->interface == PHY_INTERFACE_MODE_RMII) -+ maccr |= FTGMAC100_MACCR_RMII_ENABLE; -+ - /* Hit the HW */ - iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); - } -@@ -425,7 +455,9 @@ - priv->rx_skbs[entry] = skb; - - /* Store DMA address into RX desc */ -- rxdes->rxdes3 = cpu_to_le32(map); -+ rxdes->rxdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI, -+ upper_32_bits(map))); -+ rxdes->rxdes3 = cpu_to_le32(lower_32_bits(map)); - - /* Ensure the above is ordered vs clearing the OWN bit */ - dma_wmb(); -@@ -551,7 +583,8 @@ - csum_vlan & 0xffff); - - /* Tear down DMA mapping, do necessary cache management */ -- map = le32_to_cpu(rxdes->rxdes3); -+ map = le32_to_cpu(rxdes->rxdes3) | -+ ((le32_to_cpu(rxdes->rxdes2) & FTGMAC100_RXDES2_RXBUF_BADR_HI) << 16); - - #if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU) - /* When we don't have an iommu, we can save cycles by not -@@ -628,9 +661,12 @@ - struct ftgmac100_txdes *txdes, - u32 ctl_stat) - { -- dma_addr_t map = le32_to_cpu(txdes->txdes3); -+ dma_addr_t map; - size_t len; - -+ map = le32_to_cpu(txdes->txdes3) | -+ ((le32_to_cpu(txdes->txdes2) & FTGMAC100_TXDES2_TXBUF_BADR_HI) << 16); -+ - if (ctl_stat & FTGMAC100_TXDES0_FTS) { - len = skb_headlen(skb); - dma_unmap_single(priv->dev, map, len, DMA_TO_DEVICE); -@@ -784,7 +820,9 @@ - f_ctl_stat |= FTGMAC100_TXDES0_FTS; - if (nfrags == 0) - f_ctl_stat |= FTGMAC100_TXDES0_LTS; -- txdes->txdes3 = cpu_to_le32(map); -+ txdes->txdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI, -+ upper_32_bits((ulong)map))); -+ txdes->txdes3 = cpu_to_le32(lower_32_bits(map)); - txdes->txdes1 = cpu_to_le32(csum_vlan); - - /* Next descriptor */ -@@ -812,7 +850,9 @@ - ctl_stat |= FTGMAC100_TXDES0_LTS; - txdes->txdes0 = cpu_to_le32(ctl_stat); - txdes->txdes1 = 0; -- txdes->txdes3 = cpu_to_le32(map); -+ txdes->txdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI, -+ upper_32_bits((ulong)map))); -+ txdes->txdes3 = cpu_to_le32(lower_32_bits(map)); - - /* Next one */ - pointer = ftgmac100_next_tx_pointer(priv, pointer); -@@ -887,7 +927,10 @@ - for (i = 0; i < priv->rx_q_entries; i++) { - struct ftgmac100_rxdes *rxdes = &priv->rxdes[i]; - struct sk_buff *skb = priv->rx_skbs[i]; -- dma_addr_t map = le32_to_cpu(rxdes->rxdes3); -+ dma_addr_t map; -+ -+ map = le32_to_cpu(rxdes->rxdes3) | -+ ((le32_to_cpu(rxdes->rxdes2) & FTGMAC100_RXDES2_RXBUF_BADR_HI) << 16); - - if (!skb) - continue; -@@ -986,7 +1029,9 @@ - for (i = 0; i < priv->rx_q_entries; i++) { - rxdes = &priv->rxdes[i]; - rxdes->rxdes0 = 0; -- rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma); -+ rxdes->rxdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI, -+ upper_32_bits(priv->rx_scratch_dma))); -+ rxdes->rxdes3 = cpu_to_le32(lower_32_bits(priv->rx_scratch_dma)); - } - /* Mark the end of the ring */ - rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask); -@@ -1730,16 +1775,21 @@ - static void ftgmac100_phy_disconnect(struct net_device *netdev) - { - struct ftgmac100 *priv = netdev_priv(netdev); -+ struct phy_device *phydev = netdev->phydev; - -- if (!netdev->phydev) -- return; -+ if (priv->sgmii) { -+ phy_exit(priv->sgmii); -+ devm_phy_put(priv->dev, priv->sgmii); -+ } - -- phy_disconnect(netdev->phydev); -- if (of_phy_is_fixed_link(priv->dev->of_node)) -- of_phy_deregister_fixed_link(priv->dev->of_node); -+ if (phydev) { -+ phy_disconnect(phydev); -+ if (of_phy_is_fixed_link(priv->dev->of_node)) -+ of_phy_deregister_fixed_link(priv->dev->of_node); - -- if (priv->use_ncsi) -- fixed_phy_unregister(netdev->phydev); -+ if (priv->use_ncsi) -+ fixed_phy_unregister(phydev); -+ } - } - - static void ftgmac100_destroy_mdio(struct net_device *netdev) -@@ -1882,7 +1932,8 @@ - np = pdev->dev.of_node; - if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") || - of_device_is_compatible(np, "aspeed,ast2500-mac") || -- of_device_is_compatible(np, "aspeed,ast2600-mac"))) { -+ of_device_is_compatible(np, "aspeed,ast2600-mac") || -+ of_device_is_compatible(np, "aspeed,ast2700-mac"))) { - priv->rxdes0_edorr_mask = BIT(30); - priv->txdes0_edotr_mask = BIT(30); - priv->is_aspeed = true; -@@ -1913,40 +1964,22 @@ - goto err_phy_connect; - } - err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link, -- PHY_INTERFACE_MODE_MII); -+ PHY_INTERFACE_MODE_RMII); - if (err) { - dev_err(&pdev->dev, "Connecting PHY failed\n"); - goto err_phy_connect; - } -- } else if (np && of_phy_is_fixed_link(np)) { -- struct phy_device *phy; -- -- err = of_phy_register_fixed_link(np); -- if (err) { -- dev_err(&pdev->dev, "Failed to register fixed PHY\n"); -- goto err_phy_connect; -- } -- -- phy = of_phy_get_and_connect(priv->netdev, np, -- &ftgmac100_adjust_link); -- if (!phy) { -- dev_err(&pdev->dev, "Failed to connect to fixed PHY\n"); -- of_phy_deregister_fixed_link(np); -- err = -EINVAL; -- goto err_phy_connect; -- } -- -- /* Display what we found */ -- phy_attached_info(phy); -- } else if (np && of_get_property(np, "phy-handle", NULL)) { -+ } else if (np && (of_phy_is_fixed_link(np) || -+ of_get_property(np, "phy-handle", NULL))) { - struct phy_device *phy; - - /* Support "mdio"/"phy" child nodes for ast2400/2500 with - * an embedded MDIO controller. Automatically scan the DTS for - * available PHYs and register them. - */ -- if (of_device_is_compatible(np, "aspeed,ast2400-mac") || -- of_device_is_compatible(np, "aspeed,ast2500-mac")) { -+ if (of_get_property(np, "phy-handle", NULL) && -+ (of_device_is_compatible(np, "aspeed,ast2400-mac") || -+ of_device_is_compatible(np, "aspeed,ast2500-mac"))) { - err = ftgmac100_setup_mdio(netdev); - if (err) - goto err_setup_mdio; -@@ -1995,6 +2028,54 @@ - if (of_device_is_compatible(np, "aspeed,ast2600-mac")) - iowrite32(FTGMAC100_TM_DEFAULT, - priv->base + FTGMAC100_OFFSET_TM); -+ -+ if (of_device_is_compatible(np, "aspeed,ast2700-mac")) { -+ if (netdev->phydev->interface == PHY_INTERFACE_MODE_SGMII) { -+ priv->sgmii = devm_phy_optional_get(&pdev->dev, "sgmii"); -+ if (IS_ERR(priv->sgmii)) { -+ dev_err(priv->dev, "Failed to get sgmii phy (%ld)\n", -+ PTR_ERR(priv->sgmii)); -+ err = PTR_ERR(priv->sgmii); -+ goto err_register_netdev; -+ } -+ } -+ } -+ } -+ -+ priv->rst = devm_reset_control_get_optional_exclusive(priv->dev, NULL); -+ if (IS_ERR(priv->rst)) { -+ err = PTR_ERR(priv->rst); -+ goto err_register_netdev; -+ } -+ -+ err = reset_control_assert(priv->rst); -+ if (err) { -+ dev_err(priv->dev, "Failed to reset mac (%d)\n", err); -+ goto err_register_netdev; -+ } -+ usleep_range(10000, 20000); -+ err = reset_control_deassert(priv->rst); -+ if (err) { -+ dev_err(priv->dev, "Failed to deassert mac reset (%d)\n", err); -+ goto err_register_netdev; -+ } -+ -+ if (priv->sgmii) { -+ /* If using fixed link in dts, sgmii need to be forced */ -+ if (of_phy_is_fixed_link(np)) { -+ err = phy_set_speed(priv->sgmii, netdev->phydev->speed); -+ if (err) { -+ dev_err(priv->dev, "Failed to force sgmii speed\n"); -+ goto err_register_netdev; -+ } -+ } else { -+ /* The phy_init is used to configure Nway */ -+ err = phy_init(priv->sgmii); -+ if (err) { -+ dev_err(priv->dev, "Failed to configure sgmii Nway\n"); -+ goto err_register_netdev; -+ } -+ } - } - - /* Default ring sizes */ -@@ -2021,6 +2102,12 @@ - netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM); - netdev->features |= netdev->hw_features; - -+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -+ if (err) { -+ dev_err(&pdev->dev, "64-bit DMA enable failed\n"); -+ goto err_register_netdev; -+ } -+ - /* register network device */ - err = register_netdev(netdev); - if (err) { -diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h ---- a/drivers/net/ethernet/faraday/ftgmac100.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/net/ethernet/faraday/ftgmac100.h 2025-12-23 10:16:21.145032318 +0000 -@@ -57,6 +57,13 @@ - #define FTGMAC100_OFFSET_RX_RUNT 0xc0 - #define FTGMAC100_OFFSET_RX_CRCER_FTL 0xc4 - #define FTGMAC100_OFFSET_RX_COL_LOST 0xc8 -+/* reserved 0xcc - 0x174 */ -+#define FTGMAC100_OFFSET_TXR_BADDR_LOW 0x178 /* ast2700 */ -+#define FTGMAC100_OFFSET_TXR_BADDR_HIGH 0x17c /* ast2700 */ -+#define FTGMAC100_OFFSET_HPTXR_BADDR_LOW 0x180 /* ast2700 */ -+#define FTGMAC100_OFFSET_HPTXR_BADDR_HIGH 0x184 /* ast2700 */ -+#define FTGMAC100_OFFSET_RXR_BADDR_LOW 0x188 /* ast2700 */ -+#define FTGMAC100_OFFSET_RXR_BADDR_HIGH 0x18C /* ast2700 */ - - /* - * Interrupt status register & interrupt enable register -@@ -166,6 +173,7 @@ - #define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16) - #define FTGMAC100_MACCR_RX_BROADPKT (1 << 17) - #define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18) -+#define FTGMAC100_MACCR_RMII_ENABLE BIT(20) /* defined in ast2700 */ - #define FTGMAC100_MACCR_FAST_MODE (1 << 19) - #define FTGMAC100_MACCR_SW_RST (1 << 31) - -@@ -225,6 +233,7 @@ - #define FTGMAC100_TXDES1_TX2FIC (1 << 30) - #define FTGMAC100_TXDES1_TXIC (1 << 31) - -+#define FTGMAC100_TXDES2_TXBUF_BADR_HI GENMASK(18, 16) - /* - * Receive descriptor, aligned to 16 bytes - */ -@@ -271,4 +280,5 @@ - #define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26) - #define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27) - -+#define FTGMAC100_RXDES2_RXBUF_BADR_HI GENMASK(18, 16) - #endif /* __FTGMAC100_H */ -diff --git a/drivers/net/mctp/mctp-pcie-vdm.c b/drivers/net/mctp/mctp-pcie-vdm.c ---- a/drivers/net/mctp/mctp-pcie-vdm.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/mctp/mctp-pcie-vdm.c 2025-12-23 10:16:21.981018306 +0000 -@@ -0,0 +1,363 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * mctp-pcie-vdm.c - MCTP-over-PCIe-VDM (DMTF DSP0238) transport binding driver. -+ * -+ * DSP0238 is available at: -+ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0238_1.2.0.pdf -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MCTP_PCIE_VDM_MIN_MTU 64 -+#define MCTP_PCIE_VDM_MAX_MTU 512 -+/* 16byte */ -+#define MCTP_PCIE_VDM_HDR_SIZE 16 -+#define MCTP_PAYLOAD_IC_TYPE_SIZE 1 -+#define MCTP_RECEIVE_PKT_TIMEOUT_MS 5 -+ -+#define MCTP_PCIE_VDM_NET_DEV_TX_QUEUE_LEN 1100 -+#define MCTP_PCIE_VDM_DEV_TX_QUEUE_SIZE 64 -+ -+#define MCTP_PCIE_VDM_FMT_4DW 0x3 -+#define MCTP_PCIE_VDM_TYPE_MSG 0x10 -+#define MCTP_PCIE_VDM_CODE 0x0 -+/* PCIe VDM message code */ -+#define MCTP_PCIE_VDM_MSG_CODE 0x7F -+#define MCTP_PCIE_VDM_VENDOR_ID 0x1AB4 -+/* MCTP message type */ -+#define MCTP_MSG_TYPE_MASK GENMASK(6, 0) -+#define MCTP_PCIE_VDM_MSG_TYPE 0x7E -+ -+#define MCTP_PCIE_SWAP_NET_ENDIAN(arr, len) \ -+ do { \ -+ u32 *p = (u32 *)(arr); \ -+ for (int i = 0; i < (len); i++) { \ -+ p[i] = htonl(p[i]); \ -+ } \ -+ } while (0) -+ -+#define MCTP_PCIE_SWAP_LITTLE_ENDIAN(arr, len) \ -+ do { \ -+ u32 *p = (u32 *)(arr); \ -+ for (int i = 0; i < (len); i++) { \ -+ p[i] = ntohl(p[i]); \ -+ p[i] = cpu_to_le32(p[i]); \ -+ } \ -+ } while (0) -+ -+enum mctp_pcie_vdm_route_type { -+ MCTP_PCIE_VDM_ROUTE_TO_RC = 0, -+ MCTP_PCIE_VDM_ROUTE_BY_ID = 2, -+ MCTP_PCIE_VDM_BROADCAST_FROM_RC = 3, -+}; -+ -+enum mctp_ctrl_command_code { -+ MCTP_CTRL_CMD_SET_ENDPOINT_ID = 0x01, -+ MCTP_CTRL_CMD_GET_ENDPOINT_ID = 0x02, -+ MCTP_CTRL_CMD_PREPARE_ENDPOINT_DISCOVERY = 0x0B, -+ MCTP_CTRL_CMD_ENDPOINT_DISCOVERY = 0x0C, -+ MCTP_CTRL_CMD_DISCOVERY_NOTIFY = 0x0D -+}; -+ -+struct mctp_pcie_vdm_hdr { -+ u32 length : 10, rsvd0 : 2, attr : 2, ep : 1, td : 1, rsvd1 : 4, tc : 3, -+ rsvd2 : 1, route_type : 5, fmt : 2, rsvd3 : 1; -+ u8 msg_code; -+ u8 tag_vdm_code : 4, tag_pad_len : 2, tag_rsvd : 2; -+ u16 pci_req_id; -+ u16 pci_vendor_id; -+ u16 pci_target_id; -+}; -+ -+struct mctp_pcie_vdm_dev { -+ struct device *dev; -+ const struct mctp_pcie_vdm_ops *callback_ops; -+}; -+ -+static const struct mctp_pcie_vdm_hdr mctp_pcie_vdm_hdr_template = { -+ .fmt = MCTP_PCIE_VDM_FMT_4DW, -+ .route_type = MCTP_PCIE_VDM_TYPE_MSG | MCTP_PCIE_VDM_ROUTE_BY_ID, -+ .tag_vdm_code = MCTP_PCIE_VDM_CODE, -+ .msg_code = MCTP_PCIE_VDM_MSG_CODE, -+ .pci_vendor_id = MCTP_PCIE_VDM_VENDOR_ID, -+ .attr = 0, -+}; -+ -+static void mctp_pcie_vdm_display_skb_buff_data(struct sk_buff *skb) -+{ -+ int i = 0; -+ -+ while ((i + 4) < skb->len) { -+ pr_debug("%02x %02x %02x %02x\n", skb->data[i], -+ skb->data[i + 1], skb->data[i + 2], skb->data[i + 3]); -+ i += 4; -+ } -+ -+ char buf[16] = { 0 }; -+ char *p = buf; -+ -+ while (i < skb->len) { -+ p += snprintf(p, sizeof(buf) - (p - buf), "%02x ", -+ skb->data[i]); -+ i++; -+ } -+ pr_debug("%s\n", buf); -+} -+ -+static int mctp_pcie_vdm_xmit(struct net_device *ndev, struct sk_buff *skb) -+{ -+ struct net_device_stats *stats; -+ struct mctp_pcie_vdm_hdr *hdr; -+ struct mctp_pcie_vdm_dev *vdm_dev; -+ u8 *hdr_byte; -+ u16 payload_len_dw; -+ u16 payload_len_byte; -+ int rc; -+ -+ stats = &ndev->stats; -+ vdm_dev = netdev_priv(ndev); -+ hdr = (struct mctp_pcie_vdm_hdr *)skb->data; -+ hdr_byte = skb->data; -+ payload_len_dw = (ALIGN(skb->len, sizeof(u32)) - MCTP_PCIE_VDM_HDR_SIZE) / sizeof(u32); -+ payload_len_byte = skb->len - MCTP_PCIE_VDM_HDR_SIZE; -+ -+ hdr->length = payload_len_dw; -+ hdr->tag_pad_len = -+ ALIGN(payload_len_byte, sizeof(u32)) - payload_len_byte; -+ pr_debug("%s: skb len %d pad len %d\n", __func__, skb->len, -+ hdr->tag_pad_len); -+ MCTP_PCIE_SWAP_NET_ENDIAN((u32 *)hdr, -+ sizeof(struct mctp_pcie_vdm_hdr) / sizeof(u32)); -+ -+ mctp_pcie_vdm_display_skb_buff_data(skb); -+ rc = vdm_dev->callback_ops->send_packet(vdm_dev->dev, skb->data, payload_len_dw * sizeof(u32)); -+ -+ if (rc) { -+ pr_err("%s: failed to send packet, rc %d\n", __func__, rc); -+ stats->tx_errors++; -+ } else { -+ stats->tx_packets++; -+ stats->tx_bytes += (skb->len - sizeof(struct mctp_pcie_vdm_hdr)); -+ } -+ return rc; -+} -+ -+static netdev_tx_t mctp_pcie_vdm_start_xmit(struct sk_buff *skb, -+ struct net_device *ndev) -+{ -+ int rc; -+ netdev_tx_t ret; -+ -+ pr_debug("%s: skb len %u\n", __func__, skb->len); -+ -+ if (skb) { -+ rc = mctp_pcie_vdm_xmit(ndev, skb); -+ if (rc) { -+ pr_err("%s: failed to send packet, rc %d\n", __func__, rc); -+ ret = NETDEV_TX_BUSY; -+ } else { -+ ret = NETDEV_TX_OK; -+ kfree_skb(skb); -+ } -+ } -+ return ret; -+} -+ -+static void mctp_pcie_vdm_uninit(struct net_device *ndev) -+{ -+ struct mctp_pcie_vdm_dev *vdm_dev; -+ -+ vdm_dev = netdev_priv(ndev); -+ pr_info("%s: uninitializing vdm_dev %s\n", __func__, -+ ndev->name); -+ vdm_dev->callback_ops->uninit(vdm_dev->dev); -+} -+ -+static int mctp_pcie_vdm_hdr_create(struct sk_buff *skb, -+ struct net_device *ndev, -+ unsigned short type, const void *daddr, -+ const void *saddr, unsigned int len) -+{ -+ u8 dest_addr[3] = {0}; -+ struct mctp_pcie_vdm_hdr *hdr = -+ (struct mctp_pcie_vdm_hdr *)skb_push(skb, sizeof(*hdr)); -+ -+ pr_debug("%s type %d len %d\n", __func__, type, len); -+ memcpy(hdr, &mctp_pcie_vdm_hdr_template, sizeof(*hdr)); -+ if (daddr) { -+ memcpy(dest_addr, (u8 *)daddr, sizeof(dest_addr)); -+ hdr->route_type |= dest_addr[0] & GENMASK(2, 0); -+ hdr->pci_target_id = dest_addr[1] << 8 | dest_addr[2]; -+ pr_debug("%s dst route %d addr %d\n", __func__, hdr->route_type, hdr->pci_target_id); -+ } -+ -+ if (saddr) { -+ pr_debug("%s src addr %d\n", __func__, *(u16 *)saddr); -+ hdr->pci_req_id = *(u16 *)saddr; -+ } -+ -+ return 0; -+} -+ -+static const struct net_device_ops mctp_pcie_vdm_net_ops = { -+ .ndo_start_xmit = mctp_pcie_vdm_start_xmit, -+ .ndo_uninit = mctp_pcie_vdm_uninit, -+}; -+ -+static const struct header_ops mctp_pcie_vdm_net_hdr_ops = { -+ .create = mctp_pcie_vdm_hdr_create, -+}; -+ -+static void mctp_pcie_vdm_net_setup(struct net_device *ndev) -+{ -+ ndev->type = ARPHRD_MCTP; -+ -+ ndev->mtu = MCTP_PCIE_VDM_MIN_MTU; -+ ndev->min_mtu = MCTP_PCIE_VDM_MIN_MTU; -+ ndev->max_mtu = MCTP_PCIE_VDM_MAX_MTU; -+ ndev->tx_queue_len = MCTP_PCIE_VDM_NET_DEV_TX_QUEUE_LEN; -+ ndev->addr_len = 3; //PCIe bdf is 2bytes + 1byte route type -+ ndev->hard_header_len = sizeof(struct mctp_pcie_vdm_hdr); -+ -+ ndev->netdev_ops = &mctp_pcie_vdm_net_ops; -+ ndev->header_ops = &mctp_pcie_vdm_net_hdr_ops; -+} -+ -+static int mctp_pcie_vdm_add_net_dev(struct net_device **dev) -+{ -+ struct net_device *ndev = alloc_netdev(sizeof(struct mctp_pcie_vdm_dev), -+ "mctppci%d", NET_NAME_UNKNOWN, -+ mctp_pcie_vdm_net_setup); -+ -+ if (!ndev) { -+ pr_err("%s: failed to allocate net device\n", __func__); -+ return -ENOMEM; -+ } -+ dev_net_set(ndev, current->nsproxy->net_ns); -+ -+ *dev = ndev; -+ int rc; -+ -+ rc = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_PCIE_VDM); -+ if (rc) { -+ pr_err("%s: failed to register net device\n", __func__); -+ free_netdev(ndev); -+ return rc; -+ } -+ return rc; -+} -+ -+void mctp_pcie_vdm_receive_packet(struct net_device *ndev) -+{ -+ struct mctp_pcie_vdm_dev *vdm_dev; -+ u8 *packet; -+ -+ vdm_dev = netdev_priv(ndev); -+ packet = vdm_dev->callback_ops->recv_packet(vdm_dev->dev); -+ -+ while (!IS_ERR(packet)) { -+ MCTP_PCIE_SWAP_LITTLE_ENDIAN((u32 *)packet, -+ sizeof(struct mctp_pcie_vdm_hdr) / sizeof(u32)); -+ struct mctp_pcie_vdm_hdr *vdm_hdr = (struct mctp_pcie_vdm_hdr *)packet; -+ struct mctp_skb_cb *cb; -+ struct net_device_stats *stats; -+ struct sk_buff *skb; -+ u16 len; -+ int net_status; -+ -+ stats = &ndev->stats; -+ len = vdm_hdr->length * sizeof(u32) - -+ vdm_hdr->tag_pad_len; -+ len += (MCTP_PCIE_VDM_HDR_SIZE - sizeof(struct mctp_pcie_vdm_hdr)); -+ skb = netdev_alloc_skb(ndev, len); -+ pr_debug("%s: received packet size: %d\n", __func__, -+ len); -+ -+ if (!skb) { -+ stats->rx_errors++; -+ pr_err("%s: failed to alloc skb\n", __func__); -+ continue; -+ } -+ -+ skb->protocol = htons(ETH_P_MCTP); -+ /* put data into tail sk buff */ -+ skb_put_data(skb, &packet[sizeof(struct mctp_pcie_vdm_hdr)], len); -+ mctp_pcie_vdm_display_skb_buff_data(skb); -+ -+ cb = __mctp_cb(skb); -+ cb->halen = 3; // route type | bdf address -+ cb->haddr[0] = vdm_hdr->route_type; -+ // address is also converted to little-endian, but we want to keep it as big-endian -+ // because kernel network layer assumes address in big-endian format -+ cb->haddr[1] = vdm_hdr->pci_req_id & 0xFF; -+ cb->haddr[2] = vdm_hdr->pci_req_id >> 8; -+ -+ net_status = netif_rx(skb); -+ if (net_status == NET_RX_SUCCESS) { -+ stats->rx_packets++; -+ stats->rx_bytes += len; -+ } else { -+ stats->rx_dropped++; -+ } -+ -+ vdm_dev->callback_ops->free_packet(packet); -+ packet = vdm_dev->callback_ops->recv_packet(vdm_dev->dev); -+ } -+} -+ -+struct net_device *mctp_pcie_vdm_add_dev(struct device *dev, -+ const struct mctp_pcie_vdm_ops *ops) -+{ -+ struct net_device *ndev; -+ struct mctp_pcie_vdm_dev *vdm_dev; -+ int rc; -+ -+ rc = mctp_pcie_vdm_add_net_dev(&ndev); -+ if (rc) { -+ pr_err("%s: failed to add net device\n", __func__); -+ return ERR_PTR(rc); -+ } -+ -+ vdm_dev = netdev_priv(ndev); -+ vdm_dev->dev = dev; -+ vdm_dev->callback_ops = ops; -+ -+ return ndev; -+} -+EXPORT_SYMBOL_GPL(mctp_pcie_vdm_add_dev); -+ -+void mctp_pcie_vdm_remove_dev(struct net_device *vdm_dev) -+{ -+ pr_debug("%s: removing vdm_dev %s\n", __func__, vdm_dev->name); -+ -+ if (vdm_dev) { -+ mctp_unregister_netdev(vdm_dev); -+ free_netdev(vdm_dev); -+ } -+} -+EXPORT_SYMBOL_GPL(mctp_pcie_vdm_remove_dev); diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c ---- a/drivers/net/mdio/mdio-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/net/mdio/mdio-aspeed.c 2025-12-23 10:16:20.939035770 +0000 -@@ -62,6 +62,8 @@ +--- a/drivers/net/mdio/mdio-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/net/mdio/mdio-aspeed.c 2026-09-09 15:51:44.501241351 +0000 +@@ -62,13 +62,8 @@ | FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data); iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL); +- +- /* Workaround for read-after-write issue. +- * The controller may return stale data if a read follows immediately +- * after a write. A dummy read forces the hardware to update its +- * internal state, ensuring that the next real read returns correct data. +- */ +- ioread32(ctx->base + ASPEED_MDIO_CTRL); + /* Add dummy read to ensure triggering mdio controller */ + (void)ioread32(ctx->base + ASPEED_MDIO_CTRL); return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl, !(ctrl & ASPEED_MDIO_CTRL_FIRE), -diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig ---- a/drivers/pci/controller/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pci/controller/Kconfig 2025-12-23 10:16:09.638225214 +0000 -@@ -47,6 +47,15 @@ - - If unsure, say Y if you have an Apple Silicon system. - -+config PCIE_ASPEED -+ bool "ASPEED PCIe controller" -+ depends on PCI -+ depends on OF || COMPILE_TEST -+ select PCI_MSI_ARCH_FALLBACKS -+ help -+ Say Y here if you want PCIe controller support on -+ ASPEED SoCs. -+ - config PCI_VERSATILE - bool "ARM Versatile PB PCI controller" - depends on ARCH_VERSATILE || COMPILE_TEST -diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile ---- a/drivers/pci/controller/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pci/controller/Makefile 2025-12-23 10:16:13.816155152 +0000 -@@ -39,6 +39,7 @@ - obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o - obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o - obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o -+obj-$(CONFIG_PCIE_ASPEED) += pcie-aspeed.o - - # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW - obj-y += dwc/ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie-aspeed.c --- a/drivers/pci/controller/pcie-aspeed.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/pci/controller/pcie-aspeed.c 2025-12-23 10:16:21.109032921 +0000 -@@ -0,0 +1,1185 @@ ++++ b/drivers/pci/controller/pcie-aspeed.c 2026-09-09 15:51:44.696238404 +0000 +@@ -0,0 +1,1208 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PCIe host controller driver for ASPEED PCIe Bridge @@ -47795,6 +47846,12 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- +#define H2X_CFGE_INT_STS 0x08 +#define CFGE_TX_IDLE BIT(0) +#define CFGE_RX_BUSY BIT(1) ++#define H2X_CTRL2 0x1c ++#define CPL_TIMEOUT_MASK GENMASK(9, 8) ++#define CPL_TIMEOUT_10US 0 ++#define CPL_TIMEOUT_20US 1 ++#define CPL_TIMEOUT_40US 2 ++#define CPL_TIMEOUT_160US 3 +#define H2X_CFGI_TLP 0x20 +#define H2X_CFGI_WR_DATA 0x24 +#define H2X_CFGI_CTRL 0x28 @@ -47804,6 +47861,7 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- +#define H2X_CFGE_TLP_NEXT 0x34 +#define H2X_CFGE_CTRL 0x38 +#define CFGE_TLP_FIRE BIT(0) ++#define CFGE_TLP_RET_BYPASS BIT(1) +#define H2X_CFGE_RET_DATA 0x3C +#define H2X_REMAP_PREF_ADDR 0x70 +#define H2X_REMAP_DIRECT_ADDR 0x78 @@ -47825,6 +47883,11 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- +#define PEHR_MISC_78 0x78 +#define PEHR_MISC_1B8 0x1B8 +#define SW_ATT_BTN BIT(0) ++#define PEHR_MISC_278 0x278 ++#define SET_TO_DOWNSTREAM BIT(22) ++#define ASSERT_INTERNAL_RESET BIT(31) ++#define PEHR_MISC_280 0x280 ++#define SEL_INTERNAL_RESET BIT(0) +#define PEHR_MISC_344 0x344 +#define LINK_STATUS_GEN2 BIT(18) +#define PEHR_MISC_358 0x358 @@ -47854,6 +47917,7 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + int reg_intx_sts; + int reg_msi_en; + int reg_msi_sts; ++ int msi_support; + int msi_address; +}; + @@ -47888,14 +47952,6 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS); +}; + -+static void aspeed_pcie_intx_ack_irq(struct irq_data *d) -+{ -+ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); -+ int intx_en = pcie->platform->reg_intx_en; -+ -+ writel(readl(pcie->reg + intx_en) | BIT(d->hwirq), pcie->reg + intx_en); -+} -+ +static void aspeed_pcie_intx_mask_irq(struct irq_data *d) +{ + struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); @@ -47914,7 +47970,6 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + +static struct irq_chip aspeed_intx_irq_chip = { + .name = "ASPEED:IntX", -+ .irq_ack = aspeed_pcie_intx_ack_irq, + .irq_mask = aspeed_pcie_intx_mask_irq, + .irq_unmask = aspeed_pcie_intx_unmask_irq, +}; @@ -48237,6 +48292,7 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + "[%X:%02X:%02X.%02X]CR rx timeoutsts: 0x%08x\n", + pcie->domain, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), status); ++ writel(CFGE_TLP_RET_BYPASS, pcie->reg + H2X_CFGE_CTRL); + goto out; + } + *val = readl(pcie->reg + H2X_CFGE_RET_DATA); @@ -48478,6 +48534,9 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + writel(0, pcie->reg + pcie->platform->reg_intx_en); + writel(~0, pcie->reg + pcie->platform->reg_intx_sts); + ++ if (!pcie->platform->msi_support) ++ return 0; ++ +#ifdef CONFIG_PCI_MSI + pcie->dev_domain = + irq_domain_add_linear(NULL, MAX_MSI_HOST_IRQS, &aspeed_msi_domain_ops, pcie); @@ -48699,6 +48758,9 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + mdelay(10); + reset_control_deassert(pcie->h2xrst); + ++ regmap_write(pcie->pciephy, PEHR_MISC_278, 0); ++ if (!IS_ENABLED(CONFIG_PHY_ASPEED_COMBINE_PERST)) ++ regmap_write(pcie->pciephy, PEHR_MISC_280, SEL_INTERNAL_RESET); + regmap_write(pcie->pciephy, PEHR_MISC_5C, 0x40000000); + regmap_read(pcie->pciephy, PEHR_MISC_60, &cfg_val); + regmap_write(pcie->pciephy, PEHR_MISC_60, @@ -48707,6 +48769,9 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + writel(0, pcie->reg + H2X_CTRL); + writel(H2X_BRIDGE_EN | H2X_BRIDGE_DIRECT_EN, pcie->reg + H2X_CTRL); + ++ writel(FIELD_PREP(CPL_TIMEOUT_MASK, CPL_TIMEOUT_160US), ++ pcie->reg + H2X_CTRL2); ++ + /* The BAR mapping: + * CPU Node0(domain 0): 0x60000000 + * CPU Node1(domain 1): 0x80000000 @@ -48717,6 +48782,12 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + /* Prepare for 64-bit BAR pref */ + writel(0x3, pcie->reg + H2X_REMAP_PREF_ADDR); + ++ if (IS_ENABLED(CONFIG_PHY_ASPEED_COMBINE_PERST)) ++ regmap_write(pcie->pciephy, PEHR_MISC_278, SET_TO_DOWNSTREAM); ++ else ++ regmap_write(pcie->pciephy, PEHR_MISC_278, ++ ASSERT_INTERNAL_RESET | SET_TO_DOWNSTREAM); ++ + reset_control_deassert(pcie->perst); + if (pcie->perst_rc_out) + gpiod_set_value(pcie->perst_rc_out, 1); @@ -48732,6 +48803,7 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + ATTENTION_BUTTON_ENABLE); + regmap_write_bits(pcie->pciephy, PEHR_MISC_38, + DATALINK_REPORT_CAP, DATALINK_REPORT_CAP); ++ regmap_write(pcie->pciephy, PEHR_MISC_278, SET_TO_DOWNSTREAM); + } + + if (!aspeed_ast2700_get_link(pcie)) @@ -48858,6 +48930,7 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + .reg_intx_sts = 0x08, + .reg_msi_en = 0x20, + .reg_msi_sts = 0x28, ++ .msi_support = false, + .msi_address = 0x1e77005c, +}; + @@ -48867,6 +48940,7 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- + .reg_intx_sts = 0x48, + .reg_msi_en = 0x50, + .reg_msi_sts = 0x58, ++ .msi_support = true, + .msi_address = 0x000000f0, +}; + @@ -48887,32 +48961,10 @@ diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie- +}; + +module_platform_driver(aspeed_pcie_driver); -diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig ---- a/drivers/phy/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/phy/Kconfig 2025-12-23 10:16:09.358229909 +0000 -@@ -84,6 +84,7 @@ - - source "drivers/phy/allwinner/Kconfig" - source "drivers/phy/amlogic/Kconfig" -+source "drivers/phy/aspeed/Kconfig" - source "drivers/phy/broadcom/Kconfig" - source "drivers/phy/cadence/Kconfig" - source "drivers/phy/freescale/Kconfig" -diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile ---- a/drivers/phy/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/phy/Makefile 2025-12-23 10:16:13.519160131 +0000 -@@ -13,6 +13,7 @@ - obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o - obj-y += allwinner/ \ - amlogic/ \ -+ aspeed/ \ - broadcom/ \ - cadence/ \ - freescale/ \ diff --git a/drivers/phy/aspeed/Kconfig b/drivers/phy/aspeed/Kconfig --- a/drivers/phy/aspeed/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/phy/aspeed/Kconfig 2025-12-23 10:16:19.139065938 +0000 -@@ -0,0 +1,23 @@ ++++ b/drivers/phy/aspeed/Kconfig 2026-09-09 15:51:42.428272675 +0000 +@@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# @@ -48932,23 +48984,21 @@ diff --git a/drivers/phy/aspeed/Kconfig b/drivers/phy/aspeed/Kconfig +config PHY_ASPEED_USB3 + tristate "ASPEED USB3 PHY driver" + select GENERIC_PHY -+ depends on ARCH_ASPEED -+ default n ++ depends on (ARCH_ASPEED || COMPILE_TEST) + help -+ Enable driver support for Aspeed AST2700 PHY USB3. ++ Enable driver support for Aspeed AST2700 USB3 PHY. diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile --- a/drivers/phy/aspeed/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/phy/aspeed/Makefile 2025-12-23 10:16:19.139065938 +0000 ++++ b/drivers/phy/aspeed/Makefile 2026-09-09 15:51:42.428272675 +0000 @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + -+obj-$(CONFIG_PHY_ASPEED_SGMII) += aspeed-sgmii.o -+obj-$(CONFIG_PHY_ASPEED_USB3) += aspeed-usb-phy3.o -\ No newline at end of file -diff --git a/drivers/phy/aspeed/aspeed-sgmii.c b/drivers/phy/aspeed/aspeed-sgmii.c ---- a/drivers/phy/aspeed/aspeed-sgmii.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/phy/aspeed/aspeed-sgmii.c 2025-12-23 10:16:21.033034195 +0000 -@@ -0,0 +1,218 @@ ++obj-$(CONFIG_PHY_ASPEED_SGMII) += phy-aspeed-sgmii.o ++obj-$(CONFIG_PHY_ASPEED_USB3) += phy-aspeed-usb3.o +diff --git a/drivers/phy/aspeed/phy-aspeed-sgmii.c b/drivers/phy/aspeed/phy-aspeed-sgmii.c +--- a/drivers/phy/aspeed/phy-aspeed-sgmii.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/phy/aspeed/phy-aspeed-sgmii.c 2026-09-09 15:51:44.614239643 +0000 +@@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023 Aspeed Technology Inc. @@ -48961,135 +49011,152 @@ diff --git a/drivers/phy/aspeed/aspeed-sgmii.c b/drivers/phy/aspeed/aspeed-sgmii +#include +#include + ++#define SCU_HW_REVISION_ID GENMASK(23, 16) ++ +#define SGMII_CFG 0x00 ++#define SGMII_CFG_FIFO_MODE BIT(0) ++#define SGMII_CFG_SPEED_SEL_MASK GENMASK(5, 4) ++#define SGMII_CFG_SPEED_SEL(x) FIELD_PREP(SGMII_CFG_SPEED_SEL_MASK, (x)) ++#define SGMII_CFG_PWR_DOWN BIT(11) ++#define SGMII_CFG_AN_ENABLE BIT(12) ++#define SGMII_CFG_SW_RESET BIT(15) +#define SGMII_LINK_TIMER 0x08 +#define SGMII_NWAY_ACK 0x0c +#define SGMII_PHY_CFG1 0x18 ++#define SGMII_PHY_SPEED_MASK GENMASK(3, 2) ++#define SGMII_PHY_SPEED(x) FIELD_PREP(SGMII_PHY_SPEED_MASK, (x)) +#define SGMII_PHY_PIPE_CTL 0x20 ++#define SGMII_PCTL_TX_NO_DEEMPH BIT(7) +#define SGMII_FIFO_DELAY_THREHOLD 0x28 +#define SGMII_MODE 0x30 ++#define SGMII_MODE_ENABLE BIT(0) ++#define SGMII_MODE_USE_LOCAL_CONFIG BIT(2) + -+#define SGMII_CFG_FIFO_MODE BIT(0) -+#define SGMII_CFG_SPEED_10M 0 -+#define SGMII_CFG_SPEED_100M BIT(4) -+#define SGMII_CFG_SPEED_1G BIT(5) -+#define SGMII_CFG_PWR_DOWN BIT(11) -+#define SGMII_CFG_AN_ENABLE BIT(12) -+#define SGMII_CFG_SW_RESET BIT(15) -+#define SGMII_PCTL_TX_NO_DEEMPH BIT(7) -+#define SGMII_MODE_ENABLE BIT(0) -+#define SGMII_MODE_USE_LOCAL_CONFIG BIT(2) ++#define PEHR280 0x280 ++#define SGMII_INTERNAL_CLK_EN BIT(26) ++#define PCIEPHY_CLK 0x268 ++#define PCIEPHY_CLK_FREQ_MULTI_MASK GENMASK(7, 0) ++#define PCIEPHY_CLK_FREQ_MULTI(x) FIELD_PREP(PCIEPHY_CLK_FREQ_MULTI_MASK, (x)) ++#define PCIEPHY_CLK_SEL_INTERNAL_25M BIT(8) + -+#define PLDA_CLK 0x268 -+ -+#define PLDA_CLK_SEL_INTERNAL_25M BIT(8) -+#define PLDA_CLK_FREQ_MULTI GENMASK(7, 0) ++#define SGMII_SPEED_10M 0x00 ++#define SGMII_SPEED_100M 0x01 ++#define SGMII_SPEED_1G 0x02 + +struct aspeed_sgmii { + struct device *dev; + void __iomem *regs; -+ struct regmap *plda_regmap; ++ struct regmap *pcie_phy_regmap; ++ u8 revision; +}; + -+static void aspeed_sgmii_set_nway(struct phy *phy) ++static int aspeed_sgmii_conf(struct phy *phy, int speed) +{ + struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); -+ u32 reg; -+ -+ /* -+ * The PLDA frequency multiplication is X xor 0x19. -+ * (X xor 0x19) * clock source = data rate. -+ * SGMII data rate is 1.25G, so (0x2b xor 0x19) * 25MHz is equal 1.25G. -+ */ -+ reg = PLDA_CLK_SEL_INTERNAL_25M | FIELD_PREP(PLDA_CLK_FREQ_MULTI, 0x2b); -+ regmap_write(sgmii->plda_regmap, PLDA_CLK, reg); ++ u32 cfg; + + writel(0, sgmii->regs + SGMII_MODE); + + writel(0, sgmii->regs + SGMII_CFG); -+ reg = SGMII_CFG_SW_RESET | SGMII_CFG_PWR_DOWN; -+ writel(reg, sgmii->regs + SGMII_CFG); -+ -+ reg = SGMII_CFG_AN_ENABLE; -+ writel(reg, sgmii->regs + SGMII_CFG); -+ -+ writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); ++ if (speed == 0) { ++ /* Configure for auto-negotiation */ ++ if (sgmii->revision == 1) ++ writel(SGMII_CFG_AN_ENABLE, sgmii->regs + SGMII_CFG); ++ else ++ writel(SGMII_CFG_AN_ENABLE | SGMII_CFG_FIFO_MODE, ++ sgmii->regs + SGMII_CFG); ++ } else { ++ switch (speed) { ++ case SPEED_10: ++ cfg = SGMII_SPEED_10M; ++ break; ++ case SPEED_100: ++ cfg = SGMII_SPEED_100M; ++ break; ++ case SPEED_1000: ++ cfg = SGMII_SPEED_1G; ++ break; ++ default: ++ return -EINVAL; ++ } ++ writel(SGMII_PHY_SPEED(cfg), sgmii->regs + SGMII_PHY_CFG1); ++ if (sgmii->revision == 1) ++ writel(SGMII_CFG_SPEED_SEL(cfg), ++ sgmii->regs + SGMII_CFG); ++ else ++ writel(SGMII_CFG_SPEED_SEL(cfg) | SGMII_CFG_FIFO_MODE, ++ sgmii->regs + SGMII_CFG); ++ } + ++ if (sgmii->revision == 1) ++ writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); ++ else ++ writel(0x0e, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); + writel(SGMII_PCTL_TX_NO_DEEMPH, sgmii->regs + SGMII_PHY_PIPE_CTL); + -+ /* Set link timer for Nway state change */ ++ /* Set link timer for state change */ + writel(0x100, sgmii->regs + SGMII_LINK_TIMER); + + /* Bit 0 always sets to 1 in ACK message */ + writel(0x1, sgmii->regs + SGMII_NWAY_ACK); + -+ reg = SGMII_MODE_ENABLE; -+ writel(reg, sgmii->regs + SGMII_MODE); ++ cfg = SGMII_MODE_ENABLE; ++ if (speed) ++ cfg |= SGMII_MODE_USE_LOCAL_CONFIG; ++ writel(cfg, sgmii->regs + SGMII_MODE); ++ ++ return 0; +} + +static int aspeed_sgmii_phy_init(struct phy *phy) +{ -+ aspeed_sgmii_set_nway(phy); ++ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); ++ u32 reg; ++ ++ /* ++ * The PLDA frequency multiplication is X xor 0x19. ++ * (X xor 0x19) * clock source = data rate. ++ * SGMII data rate is 1.25G, so (0x2b xor 0x19) * 25MHz is equal 1.25G. ++ */ ++ reg = PCIEPHY_CLK_SEL_INTERNAL_25M | PCIEPHY_CLK_FREQ_MULTI(0x2b); ++ regmap_write(sgmii->pcie_phy_regmap, PCIEPHY_CLK, reg); ++ if (sgmii->revision > 1) { ++ regmap_read(sgmii->pcie_phy_regmap, PEHR280, ®); ++ reg |= SGMII_INTERNAL_CLK_EN; ++ regmap_write(sgmii->pcie_phy_regmap, PEHR280, reg); ++ } + + return 0; +} + -+static int aspeed_sgmii_phy_exit(struct phy *phy) ++static int aspeed_sgmii_phy_reset(struct phy *phy) +{ + struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); + -+ /* Disable SGMII controller */ -+ writel(0, sgmii->regs + SGMII_MODE); ++ writel(SGMII_CFG_PWR_DOWN, sgmii->regs + SGMII_CFG); ++ writel(0, sgmii->regs + SGMII_CFG); + + return 0; +} + +static int aspeed_sgmii_phy_set_speed(struct phy *phy, int speed) +{ -+ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); -+ u32 reg; -+ -+ reg = PLDA_CLK_SEL_INTERNAL_25M | FIELD_PREP(PLDA_CLK_FREQ_MULTI, 0x2b); -+ regmap_write(sgmii->plda_regmap, PLDA_CLK, reg); ++ return aspeed_sgmii_conf(phy, speed); ++} + -+ switch (speed) { -+ case SPEED_10: -+ reg = SGMII_CFG_SPEED_10M; -+ break; -+ case SPEED_100: -+ reg = SGMII_CFG_SPEED_100M; -+ break; -+ case SPEED_1000: -+ reg = SGMII_CFG_SPEED_1G; -+ break; -+ default: -+ return -EINVAL; -+ } ++static int aspeed_sgmii_phy_exit(struct phy *phy) ++{ ++ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); + ++ /* Disable SGMII controller */ + writel(0, sgmii->regs + SGMII_MODE); + -+ writel((reg >> 2), sgmii->regs + SGMII_PHY_CFG1); -+ -+ writel(0, sgmii->regs + SGMII_CFG); -+ writel(SGMII_CFG_SW_RESET | SGMII_CFG_PWR_DOWN, sgmii->regs + SGMII_CFG); -+ writel(reg, sgmii->regs + SGMII_CFG); -+ -+ writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); -+ writel(SGMII_PCTL_TX_NO_DEEMPH, sgmii->regs + SGMII_PHY_PIPE_CTL); -+ -+ /* Set link timer for Nway state change */ -+ writel(0x100, sgmii->regs + SGMII_LINK_TIMER); -+ -+ /* Bit 0 always sets to 1 in ACK message */ -+ writel(0x1, sgmii->regs + SGMII_NWAY_ACK); -+ -+ writel(SGMII_MODE_ENABLE | SGMII_MODE_USE_LOCAL_CONFIG, sgmii->regs + SGMII_MODE); -+ + return 0; +} + +static const struct phy_ops aspeed_sgmii_phyops = { + .init = aspeed_sgmii_phy_init, ++ .reset = aspeed_sgmii_phy_reset, + .set_speed = aspeed_sgmii_phy_set_speed, + .exit = aspeed_sgmii_phy_exit, + .owner = THIS_MODULE, @@ -49097,12 +49164,14 @@ diff --git a/drivers/phy/aspeed/aspeed-sgmii.c b/drivers/phy/aspeed/aspeed-sgmii + +static int aspeed_sgmii_probe(struct platform_device *pdev) +{ ++ struct phy_provider *provider; + struct aspeed_sgmii *sgmii; ++ struct regmap *scu_regmap; ++ struct device_node *np; + struct resource *res; + struct device *dev; -+ struct device_node *np; -+ struct phy_provider *provider; + struct phy *phy; ++ u32 reg; + + dev = &pdev->dev; + @@ -49125,13 +49194,23 @@ diff --git a/drivers/phy/aspeed/aspeed-sgmii.c b/drivers/phy/aspeed/aspeed-sgmii + } + + np = pdev->dev.of_node; -+ sgmii->plda_regmap = syscon_regmap_lookup_by_phandle(np, "aspeed,plda"); -+ if (IS_ERR(sgmii->plda_regmap)) { -+ dev_err(sgmii->dev, "Unable to find plda regmap (%ld)\n", -+ PTR_ERR(sgmii->plda_regmap)); -+ return PTR_ERR(sgmii->plda_regmap); ++ sgmii->pcie_phy_regmap = syscon_regmap_lookup_by_phandle(np, "phys"); ++ if (IS_ERR(sgmii->pcie_phy_regmap)) { ++ dev_err(sgmii->dev, "Unable to find phys regmap (%ld)\n", ++ PTR_ERR(sgmii->pcie_phy_regmap)); ++ return PTR_ERR(sgmii->pcie_phy_regmap); + } + ++ scu_regmap = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); ++ if (IS_ERR(scu_regmap)) { ++ dev_err(sgmii->dev, "Unable to find SCU regmap (%ld)\n", ++ PTR_ERR(scu_regmap)); ++ return PTR_ERR(scu_regmap); ++ } ++ ++ regmap_read(scu_regmap, 0x00, ®); ++ sgmii->revision = FIELD_GET(SCU_HW_REVISION_ID, reg); ++ + phy = devm_phy_create(dev, NULL, &aspeed_sgmii_phyops); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); @@ -49165,272 +49244,251 @@ diff --git a/drivers/phy/aspeed/aspeed-sgmii.c b/drivers/phy/aspeed/aspeed-sgmii +module_platform_driver(aspeed_sgmii_driver); + +MODULE_AUTHOR("Jacky Chou "); -+MODULE_DESCRIPTION("Control of ASPEED SGMII Device"); ++MODULE_DESCRIPTION("ASPEED SGMII Serdes/PHY controller"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/phy/aspeed/aspeed-usb-phy3.c b/drivers/phy/aspeed/aspeed-usb-phy3.c ---- a/drivers/phy/aspeed/aspeed-usb-phy3.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/phy/aspeed/aspeed-usb-phy3.c 2025-12-23 10:16:21.038034111 +0000 -@@ -0,0 +1,257 @@ +diff --git a/drivers/phy/aspeed/phy-aspeed-usb3.c b/drivers/phy/aspeed/phy-aspeed-usb3.c +--- a/drivers/phy/aspeed/phy-aspeed-usb3.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/phy/aspeed/phy-aspeed-usb3.c 2026-09-09 15:51:44.620239552 +0000 +@@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* -+ * Copyright 2023 Aspeed Technology Inc. ++ * Copyright 2026 Aspeed Technology Inc. + */ + -+#include ++#include ++#include ++#include ++#include +#include -+#include +#include -+#include -+#include -+#include -+#include -+#include -+#include +#include ++#include ++#include + -+#define PHY3P00_DEFAULT 0xCE70000F /* PHY PCS Protocol Setting #1 default value */ -+#define PHY3P04_DEFAULT 0x49C00014 /* PHY PCS Protocol Setting #2 default value */ -+#define PHY3P08_DEFAULT 0x5E406825 /* PHY PCS Protocol Setting #3 default value */ -+#define PHY3P0C_DEFAULT 0x00000001 /* PHY PCS Protocol Setting #4 default value */ -+ -+#define DWC_CRTL_NUM 3 -+ -+#define USB_PHY3_INIT_DONE BIT(15) /* BIT15: USB3.1 Phy internal SRAM initialization done */ -+#define USB_PHY3_SRAM_BYPASS BIT(7) /* USB3.1 Phy SRAM bypass */ -+#define USB_PHY3_SRAM_EXT_LOAD BIT(6) /* USB3.1 Phy SRAM external load done */ -+ -+struct aspeed_usb_phy3 { -+ struct device *dev; ++#define PHY3S00 0x00 ++#define PHY3S00_INIT_DONE BIT(15) ++#define PHY3S00_SRAM_BYPASS BIT(7) ++#define PHY3S00_SRAM_EXT_LOAD BIT(6) ++#define PHY3S04 0x04 ++#define PHY3C00 0x08 ++#define PHY3C04 0x0C ++#define PHY3P00 0x10 ++#define PHY3P00_RX_ADAPT_AFE_EN_G1 BIT(0) ++#define PHY3P00_RX_ADAPT_AFE_EN_G2 BIT(1) ++#define PHY3P00_RX_ADAPT_DFE_EN_G1 BIT(2) ++#define PHY3P00_RX_ADAPT_DFE_EN_G2 BIT(3) ++#define PHY3P00_RX_CDR_VCO_LOWFREQ_G1 BIT(4) ++#define PHY3P00_RX_CDR_VCO_LOWFREQ_G2 BIT(5) ++#define PHY3P00_RX_EQ_AFE_GAIN_G1 GENMASK(9, 6) ++#define PHY3P00_RX_EQ_AFE_GAIN_G2 GENMASK(13, 10) ++#define PHY3P00_RX_EQ_ATT_LVL_G1 GENMASK(16, 14) ++#define PHY3P00_RX_EQ_ATT_LVL_G2 GENMASK(19, 17) ++#define PHY3P00_RX_EQ_CTLE_BOOST_G1 GENMASK(24, 20) ++#define PHY3P00_RX_EQ_CTLE_BOOST_G2 GENMASK(29, 25) ++#define PHY3P00_RX_EQ_DELTA_IQ_G1_LO GENMASK(31, 30) ++ ++#define PHY3P04 0x14 ++#define PHY3P04_RX_EQ_DELTA_IQ_G1_HI GENMASK(1, 0) ++#define PHY3P04_RX_EQ_DELTA_IQ_G2 GENMASK(5, 2) ++#define PHY3P04_RX_EQ_DFE_TAP1_G1 GENMASK(13, 6) ++#define PHY3P04_RX_EQ_DFE_TAP1_G2 GENMASK(21, 14) ++#define PHY3P04_RX_LOS_LFPS_EN BIT(22) ++#define PHY3P04_RX_LOS_THRESHOLD GENMASK(25, 23) ++#define PHY3P04_RX_TERM_CTRL GENMASK(28, 26) ++#define PHY3P04_TX_EQ_MAIN_G1_LO GENMASK(31, 29) ++ ++#define PHY3P08 0x18 ++#define PHY3P08_TX_EQ_MAIN_G1_HI GENMASK(1, 0) ++#define PHY3P08_TX_EQ_MAIN_G2 GENMASK(6, 2) ++#define PHY3P08_TX_EQ_OVRD BIT(7) ++#define PHY3P08_TX_EQ_POST_G1 GENMASK(12, 9) ++#define PHY3P08_TX_EQ_POST_G2 GENMASK(16, 13) ++#define PHY3P08_TX_EQ_PRE_G1 GENMASK(20, 17) ++#define PHY3P08_TX_EQ_PRE_G2 GENMASK(24, 21) ++#define PHY3P08_TX_IBOOST_LVL GENMASK(28, 25) ++#define PHY3P08_TX_TERM_CTRL GENMASK(31, 29) ++ ++#define PHY3P0C 0x1C ++#define PHY3P0C_TX_VBOOST_EN BIT(0) ++ ++#define PHY3CMD 0x40 ++ ++#define PHY3P_RX_EQ_CTLE_BOOST_G1_DEFAULT 0x7 ++#define PHY3P_RX_EQ_CTLE_BOOST_G2_DEFAULT 0x7 ++#define PHY3P_RX_EQ_DELTA_IQ_G1_DEFAULT 0x3 ++#define PHY3P_RX_EQ_DELTA_IQ_G2_DEFAULT 0x5 ++#define PHY3P_RX_LOS_THRESHOLD_DEFAULT 0x3 ++#define PHY3P_RX_TERM_CTRL_DEFAULT 0x2 ++#define PHY3P_TX_EQ_MAIN_G1_DEFAULT 0xa ++#define PHY3P_TX_EQ_MAIN_G2_DEFAULT 0x9 ++#define PHY3P_TX_EQ_POST_G1_DEFAULT 0x4 ++#define PHY3P_TX_EQ_POST_G2_DEFAULT 0x3 ++#define PHY3P_TX_EQ_PRE_G2_DEFAULT 0x2 ++#define PHY3P_TX_IBOOST_LVL_DEFAULT 0xf ++#define PHY3P_TX_TERM_CTRL_DEFAULT 0x2 ++ ++#define PHY3P00_DEFAULT ( \ ++ PHY3P00_RX_ADAPT_AFE_EN_G1 | \ ++ PHY3P00_RX_ADAPT_AFE_EN_G2 | \ ++ PHY3P00_RX_ADAPT_DFE_EN_G1 | \ ++ PHY3P00_RX_ADAPT_DFE_EN_G2 | \ ++ FIELD_PREP(PHY3P00_RX_EQ_CTLE_BOOST_G1, PHY3P_RX_EQ_CTLE_BOOST_G1_DEFAULT) | \ ++ FIELD_PREP(PHY3P00_RX_EQ_CTLE_BOOST_G2, PHY3P_RX_EQ_CTLE_BOOST_G2_DEFAULT) | \ ++ FIELD_PREP(PHY3P00_RX_EQ_DELTA_IQ_G1_LO, \ ++ PHY3P_RX_EQ_DELTA_IQ_G1_DEFAULT & 0x3) \ ++) ++ ++#define PHY3P04_DEFAULT ( \ ++ FIELD_PREP(PHY3P04_RX_EQ_DELTA_IQ_G1_HI, \ ++ PHY3P_RX_EQ_DELTA_IQ_G1_DEFAULT >> 2) | \ ++ FIELD_PREP(PHY3P04_RX_EQ_DELTA_IQ_G2, PHY3P_RX_EQ_DELTA_IQ_G2_DEFAULT) | \ ++ PHY3P04_RX_LOS_LFPS_EN | \ ++ FIELD_PREP(PHY3P04_RX_LOS_THRESHOLD, PHY3P_RX_LOS_THRESHOLD_DEFAULT) | \ ++ FIELD_PREP(PHY3P04_RX_TERM_CTRL, PHY3P_RX_TERM_CTRL_DEFAULT) | \ ++ FIELD_PREP(PHY3P04_TX_EQ_MAIN_G1_LO, \ ++ PHY3P_TX_EQ_MAIN_G1_DEFAULT & 0x7) \ ++) ++ ++#define PHY3P08_DEFAULT ( \ ++ FIELD_PREP(PHY3P08_TX_EQ_MAIN_G1_HI, PHY3P_TX_EQ_MAIN_G1_DEFAULT >> 3) | \ ++ FIELD_PREP(PHY3P08_TX_EQ_MAIN_G2, PHY3P_TX_EQ_MAIN_G2_DEFAULT) | \ ++ FIELD_PREP(PHY3P08_TX_EQ_POST_G1, PHY3P_TX_EQ_POST_G1_DEFAULT) | \ ++ FIELD_PREP(PHY3P08_TX_EQ_POST_G2, PHY3P_TX_EQ_POST_G2_DEFAULT) | \ ++ FIELD_PREP(PHY3P08_TX_EQ_PRE_G2, PHY3P_TX_EQ_PRE_G2_DEFAULT) | \ ++ FIELD_PREP(PHY3P08_TX_IBOOST_LVL, PHY3P_TX_IBOOST_LVL_DEFAULT) | \ ++ FIELD_PREP(PHY3P08_TX_TERM_CTRL, PHY3P_TX_TERM_CTRL_DEFAULT) \ ++) ++ ++#define PHY3P0C_DEFAULT \ ++ PHY3P0C_TX_VBOOST_EN ++ ++struct aspeed_usb3_phy { + void __iomem *regs; -+ const struct aspeed_usb_phy3_model *model; -+ bool phy_ext_load_quirk; -+}; -+ -+struct usb_dwc3_ctrl { -+ u32 offset; -+ u32 value; -+}; -+ -+struct aspeed_usb_phy3_model { -+ /* offsets to the PHY3 registers */ -+ unsigned int phy3s00; /* PHY SRAM Control/Status #1 */ -+ unsigned int phy3s04; /* PHY SRAM Control/Status #2 */ -+ unsigned int phy3c00; /* PHY PCS Control/Status #1 */ -+ unsigned int phy3c04; /* PHY PCS Control/Status #2 */ -+ unsigned int phy3p00; /* PHY PCS Protocol Setting #1 */ -+ unsigned int phy3p04; /* PHY PCS Protocol Setting #2 */ -+ unsigned int phy3p08; /* PHY PCS Protocol Setting #3 */ -+ unsigned int phy3p0c; /* PHY PCS Protocol Setting #4 */ -+ unsigned int dwc_cmd; /* DWC3 Commands base address offest */ -+}; -+ -+static struct usb_dwc3_ctrl ctrl_data[DWC_CRTL_NUM] = { -+ {0xc100, 0x00000006}, /* Set DWC3 GSBUSCFG0 for Bus Burst Type */ -+ {0xc12c, 0x0c854802}, /* Set DWC3 GUCTL for ref_clk */ -+ {0xc630, 0x0c800020}, /* Set DWC3 GLADJ for ref_clk */ -+}; -+ -+static const struct aspeed_usb_phy3_model ast2700a0_model = { -+ .phy3s00 = 0x800, -+ .phy3s04 = 0x804, -+ .phy3c00 = 0x808, -+ .phy3c04 = 0x80C, -+ .phy3p00 = 0x810, -+ .phy3p04 = 0x814, -+ .phy3p08 = 0x818, -+ .phy3p0c = 0x81C, -+ .dwc_cmd = 0xB80, -+}; -+ -+static const struct aspeed_usb_phy3_model ast2700_model = { -+ .phy3s00 = 0x00, -+ .phy3s04 = 0x04, -+ .phy3c00 = 0x08, -+ .phy3c04 = 0x0C, -+ .phy3p00 = 0x10, -+ .phy3p04 = 0x14, -+ .phy3p08 = 0x18, -+ .phy3p0c = 0x1C, -+ .dwc_cmd = 0x40, -+}; -+ -+static const struct of_device_id aspeed_usb_phy3_dt_ids[] = { -+ { -+ .compatible = "aspeed,ast2700-a0-uhy3a", -+ .data = &ast2700a0_model -+ }, -+ { -+ .compatible = "aspeed,ast2700-a0-uhy3b", -+ .data = &ast2700a0_model -+ }, -+ { -+ .compatible = "aspeed,ast2700-uphy3a", -+ .data = &ast2700_model -+ }, -+ { -+ .compatible = "aspeed,ast2700-uphy3b", -+ .data = &ast2700_model -+ }, -+ { } ++ struct reset_control *rst; ++ struct device *dev; ++ struct clk *clk; +}; -+MODULE_DEVICE_TABLE(of, aspeed_usb_phy3_dt_ids); + -+static int aspeed_usb_phy3_init(struct phy *phy) ++static int aspeed_usb3_phy_init(struct phy *phy) +{ -+ struct aspeed_usb_phy3 *phy3 = phy_get_drvdata(phy); -+ const struct aspeed_usb_phy3_model *model = phy3->model; ++ struct aspeed_usb3_phy *aspeed_phy = phy_get_drvdata(phy); + u32 val; -+ int timeout = 100; -+ int i, j; ++ int ret; + -+ while ((readl(phy3->regs + model->phy3s00) & USB_PHY3_INIT_DONE) -+ != USB_PHY3_INIT_DONE) { -+ usleep_range(100, 110); -+ if (--timeout == 0) { -+ dev_err(phy3->dev, "Wait phy3 init timed out\n"); -+ return -ETIMEDOUT; -+ } ++ ret = clk_prepare_enable(aspeed_phy->clk); ++ if (ret) { ++ dev_err(aspeed_phy->dev, "Failed to enable clock %d\n", ret); ++ return ret; ++ } ++ ++ ret = reset_control_deassert(aspeed_phy->rst); ++ if (ret) { ++ clk_disable_unprepare(aspeed_phy->clk); ++ return ret; + } + -+ val = readl(phy3->regs + model->phy3s00); ++ /* Wait for USB3 PHY internal SRAM initialization done */ ++ ret = readl_poll_timeout(aspeed_phy->regs + PHY3S00, val, ++ val & PHY3S00_INIT_DONE, ++ USEC_PER_MSEC, 10 * USEC_PER_MSEC); ++ if (ret) { ++ dev_err(aspeed_phy->dev, "SRAM init timeout\n"); ++ goto err_assert_reset; ++ } + -+ if (phy3->phy_ext_load_quirk) -+ val |= USB_PHY3_SRAM_EXT_LOAD; -+ else -+ val |= USB_PHY3_SRAM_BYPASS; -+ writel(val, phy3->regs + model->phy3s00); ++ val = readl(aspeed_phy->regs + PHY3S00); ++ val |= PHY3S00_SRAM_BYPASS; ++ writel(val, aspeed_phy->regs + PHY3S00); + + /* Set protocol1_ext signals as default PHY3 settings based on SNPS documents. + * Including PCFGI[54]: protocol1_ext_rx_los_lfps_en for better compatibility + */ -+ writel(PHY3P00_DEFAULT, phy3->regs + model->phy3p00); -+ writel(PHY3P04_DEFAULT, phy3->regs + model->phy3p04); -+ writel(PHY3P08_DEFAULT, phy3->regs + model->phy3p08); -+ writel(PHY3P0C_DEFAULT, phy3->regs + model->phy3p0c); -+ -+ /* xHCI DWC specific command initially set when PCIe xHCI enable */ -+ for (i = 0, j = model->dwc_cmd; i < DWC_CRTL_NUM; i++) { -+ /* 48-bits Command: -+ * CMD1: Data -> DWC CMD [31:0], Address -> DWC CMD [47:32] -+ * CMD2: Data -> DWC CMD [79:48], Address -> DWC CMD [95:80] -+ * ... and etc. -+ */ -+ if (i % 2 == 0) { -+ writel(ctrl_data[i].value, phy3->regs + j); -+ j += 4; ++ writel(PHY3P00_DEFAULT, aspeed_phy->regs + PHY3P00); ++ writel(PHY3P04_DEFAULT, aspeed_phy->regs + PHY3P04); ++ writel(PHY3P08_DEFAULT, aspeed_phy->regs + PHY3P08); ++ writel(PHY3P0C_DEFAULT, aspeed_phy->regs + PHY3P0C); + -+ writel(ctrl_data[i].offset & 0xFFFF, phy3->regs + j); -+ } else { -+ val = readl(phy3->regs + j) & 0xFFFF; -+ val |= ((ctrl_data[i].value & 0xFFFF) << 16); -+ writel(val, phy3->regs + j); -+ j += 4; ++ return 0; + -+ val = (ctrl_data[i].offset << 16) | (ctrl_data[i].value >> 16); -+ writel(val, phy3->regs + j); -+ j += 4; -+ } -+ } ++err_assert_reset: ++ reset_control_assert(aspeed_phy->rst); ++ clk_disable_unprepare(aspeed_phy->clk); ++ return ret; ++} ++ ++static int aspeed_usb3_phy_exit(struct phy *phy) ++{ ++ struct aspeed_usb3_phy *aspeed_phy = phy_get_drvdata(phy); ++ ++ reset_control_assert(aspeed_phy->rst); ++ clk_disable_unprepare(aspeed_phy->clk); + -+ dev_info(phy3->dev, "Initialized USB PHY3\n"); + return 0; +} + -+static const struct phy_ops aspeed_usb_phy3_phyops = { -+ .init = aspeed_usb_phy3_init, ++static const struct phy_ops aspeed_usb3_phy_ops = { ++ .init = aspeed_usb3_phy_init, ++ .exit = aspeed_usb3_phy_exit, + .owner = THIS_MODULE, +}; + -+static int aspeed_usb_phy3_probe(struct platform_device *pdev) ++static int aspeed_usb3_phy_probe(struct platform_device *pdev) +{ -+ struct aspeed_usb_phy3 *phy3; -+ struct device *dev; -+ struct phy_provider *provider; ++ struct aspeed_usb3_phy *aspeed_phy; ++ struct phy_provider *phy_provider; ++ struct device *dev = &pdev->dev; + struct phy *phy; -+ struct device_node *node = pdev->dev.of_node; -+ struct clk *clk; -+ struct reset_control *rst; -+ int rc = 0; -+ -+ dev = &pdev->dev; + -+ phy3 = devm_kzalloc(dev, sizeof(*phy3), GFP_KERNEL); -+ if (!phy3) ++ aspeed_phy = devm_kzalloc(dev, sizeof(*aspeed_phy), GFP_KERNEL); ++ if (!aspeed_phy) + return -ENOMEM; + -+ phy3->dev = dev; -+ -+ phy3->model = of_device_get_match_data(dev); -+ if (IS_ERR(phy3->model)) { -+ dev_err(dev, "Couldn't get model data\n"); -+ return -ENODEV; -+ } -+ -+ clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ -+ rc = clk_prepare_enable(clk); -+ if (rc) { -+ dev_err(dev, "Unable to enable clock (%d)\n", rc); -+ return rc; -+ } ++ aspeed_phy->dev = dev; + -+ rst = devm_reset_control_get_shared(dev, NULL); -+ if (IS_ERR(rst)) { -+ rc = PTR_ERR(rst); -+ goto err; -+ } -+ rc = reset_control_deassert(rst); -+ if (rc) -+ goto err; ++ aspeed_phy->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(aspeed_phy->clk)) ++ return PTR_ERR(aspeed_phy->clk); + -+ phy3->regs = of_iomap(node, 0); ++ aspeed_phy->rst = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(aspeed_phy->rst)) ++ return PTR_ERR(aspeed_phy->rst); + -+ phy3->phy_ext_load_quirk = -+ device_property_read_bool(dev, "aspeed,phy_ext_load_quirk"); ++ aspeed_phy->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(aspeed_phy->regs)) ++ return PTR_ERR(aspeed_phy->regs); + -+ phy = devm_phy_create(dev, NULL, &aspeed_usb_phy3_phyops); -+ if (IS_ERR(phy)) { -+ dev_err(dev, "failed to create PHY\n"); ++ phy = devm_phy_create(dev, NULL, &aspeed_usb3_phy_ops); ++ if (IS_ERR(phy)) + return PTR_ERR(phy); -+ } -+ -+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -+ if (IS_ERR(provider)) -+ return PTR_ERR(provider); + -+ phy_set_drvdata(phy, phy3); ++ phy_set_drvdata(phy, aspeed_phy); + -+ dev_info(phy3->dev, "Probed USB PHY3\n"); -+ -+ return 0; -+ -+err: -+ if (clk) -+ clk_disable_unprepare(clk); -+ return rc; ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ return PTR_ERR_OR_ZERO(phy_provider); +} + -+static void aspeed_usb_phy3_remove(struct platform_device *pdev) -+{ -+} ++static const struct of_device_id aspeed_usb3_phy_match_table[] = { ++ { ++ .compatible = "aspeed,ast2700-usb3-phy", ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_usb3_phy_match_table); + -+static struct platform_driver aspeed_usb_phy3_driver = { -+ .probe = aspeed_usb_phy3_probe, -+ .remove = aspeed_usb_phy3_remove, ++static struct platform_driver aspeed_usb3_phy_driver = { ++ .probe = aspeed_usb3_phy_probe, + .driver = { + .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_usb_phy3_dt_ids, ++ .of_match_table = aspeed_usb3_phy_match_table, + }, +}; -+module_platform_driver(aspeed_usb_phy3_driver); ++module_platform_driver(aspeed_usb3_phy_driver); + +MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Joe Wang "); ++MODULE_DESCRIPTION("ASPEED USB3.0 PHY Driver"); diff --git a/drivers/pinctrl/aspeed/Kconfig b/drivers/pinctrl/aspeed/Kconfig ---- a/drivers/pinctrl/aspeed/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/Kconfig 2025-12-23 10:16:21.135032485 +0000 +--- a/drivers/pinctrl/aspeed/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pinctrl/aspeed/Kconfig 2026-09-09 15:51:44.731237875 +0000 @@ -31,3 +31,11 @@ help Say Y here to enable pin controller support for Aspeed's 6th @@ -49444,8 +49502,8 @@ diff --git a/drivers/pinctrl/aspeed/Kconfig b/drivers/pinctrl/aspeed/Kconfig + Say Y here to enable pin controller support for Aspeed's 7th + generation SoCs. GPIO is provided by a separate GPIO driver. diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile ---- a/drivers/pinctrl/aspeed/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/Makefile 2025-12-23 10:16:21.135032485 +0000 +--- a/drivers/pinctrl/aspeed/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pinctrl/aspeed/Makefile 2026-09-09 15:51:44.731237875 +0000 @@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o @@ -49453,8 +49511,8 @@ diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile +obj-$(CONFIG_PINCTRL_ASPEED_G7) += pinctrl-aspeed-g7-soc0.o pinctrl-aspeed-g7-soc1.o pinctrl-aspeed-g7-ltpi.o \ No newline at end of file diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c ---- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c 2025-12-23 10:16:21.136032468 +0000 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c 2026-09-09 15:51:44.732237860 +0000 @@ -17,6 +17,8 @@ #include "../pinctrl-utils.h" #include "pinctrl-aspeed.h" @@ -50592,8 +50650,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, Y1, Y4, SCU40C, 4), diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c 2025-12-23 10:16:21.136032468 +0000 -@@ -0,0 +1,1156 @@ ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c 2026-09-09 15:51:44.732237860 +0000 +@@ -0,0 +1,1528 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include @@ -50650,6 +50708,13 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a +#define SCU474 0x474 /* Multi-function Pin Control #30 */ +#define SCU478 0x478 /* Multi-function Pin Control #31 */ +#define SCU47C 0x47C ++#define SCU480 0x480 /* Disable Pull-Down Control #1 */ ++#define SCU484 0x484 /* Disable Pull-Down Control #2 */ ++#define SCU488 0x488 /* Disable Pull-Down Control #3 */ ++#define SCU48C 0x48C /* Disable Pull-Down Control #4 */ ++#define SCU490 0x490 /* Disable Pull-Down Control #5 */ ++#define SCU494 0x494 /* Disable Pull-Down Control #6 */ ++#define SCU498 0x498 /* Disable Pull-Down Control #7 */ +#define SCU4A0 0x4A0 /* Voltage Selection */ +#define SCU4C0 0x4C0 /* Driving Strength #0 A-I */ +#define SCU4C4 0x4C4 /* Driving Strength #1 J-K */ @@ -50799,16 +50864,24 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a + C1, + E5, + HOLE18, -+ C11, -+ D11, + HOLE19, + HOLE20, -+ C10, -+ D10, + HOLE21, + HOLE22, + HOLE23, + HOLE24, ++ HOLE25, ++ HOLE26, ++ C11, ++ D11, ++ HOLE27, ++ HOLE28, ++ C10, ++ D10, ++ HOLE29, ++ HOLE30, ++ HOLE31, ++ HOLE32, + D9, + E9, + C9, @@ -50819,10 +50892,10 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a + A12, + A11, + D7, -+ HOLE25, -+ HOLE26, -+ HOLE27, -+ HOLE28, ++ HOLE33, ++ HOLE34, ++ HOLE35, ++ HOLE36, + G2, + G1, + G4, @@ -51347,16 +51420,24 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a + PINCTRL_PIN(C1, "C1"), + PINCTRL_PIN(E5, "E5"), + PINCTRL_PIN(HOLE18, "HOLE18"), -+ PINCTRL_PIN(C11, "C11"), -+ PINCTRL_PIN(D11, "D11"), + PINCTRL_PIN(HOLE19, "HOLE19"), + PINCTRL_PIN(HOLE20, "HOLE20"), -+ PINCTRL_PIN(C10, "C10"), -+ PINCTRL_PIN(D10, "D10"), + PINCTRL_PIN(HOLE21, "HOLE21"), + PINCTRL_PIN(HOLE22, "HOLE22"), + PINCTRL_PIN(HOLE23, "HOLE23"), + PINCTRL_PIN(HOLE24, "HOLE24"), ++ PINCTRL_PIN(HOLE25, "HOLE25"), ++ PINCTRL_PIN(HOLE26, "HOLE26"), ++ PINCTRL_PIN(C11, "C11"), ++ PINCTRL_PIN(D11, "D11"), ++ PINCTRL_PIN(HOLE27, "HOLE27"), ++ PINCTRL_PIN(HOLE28, "HOLE28"), ++ PINCTRL_PIN(C10, "C10"), ++ PINCTRL_PIN(D10, "D10"), ++ PINCTRL_PIN(HOLE29, "HOLE29"), ++ PINCTRL_PIN(HOLE30, "HOLE30"), ++ PINCTRL_PIN(HOLE31, "HOLE31"), ++ PINCTRL_PIN(HOLE32, "HOLE32"), + PINCTRL_PIN(D9, "D9"), + PINCTRL_PIN(E9, "E9"), + PINCTRL_PIN(C9, "C9"), @@ -51367,10 +51448,10 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a + PINCTRL_PIN(A12, "A12"), + PINCTRL_PIN(A11, "A11"), + PINCTRL_PIN(D7, "D7"), -+ PINCTRL_PIN(HOLE25, "HOLE25"), -+ PINCTRL_PIN(HOLE26, "HOLE26"), -+ PINCTRL_PIN(HOLE27, "HOLE27"), -+ PINCTRL_PIN(HOLE28, "HOLE28"), ++ PINCTRL_PIN(HOLE33, "HOLE33"), ++ PINCTRL_PIN(HOLE34, "HOLE34"), ++ PINCTRL_PIN(HOLE35, "HOLE35"), ++ PINCTRL_PIN(HOLE36, "HOLE36"), + PINCTRL_PIN(G2, "G2"), + PINCTRL_PIN(G1, "G1"), + PINCTRL_PIN(G4, "G4"), @@ -51658,6 +51739,351 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a + PINCFG_PIN(E15), +}; + ++static struct aspeed_pin_config aspeed_g7_ltpi_configs[] = { ++ /* GPIOA */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D6, D6 }, SCU4C0, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B7, B7 }, SCU4C0, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A7, A7 }, SCU4C0, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C6, C6 }, SCU4C0, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B6, B6 }, SCU4C0, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A6, A6 }, SCU4C0, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C5, C5 }, SCU4C0, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D5, D5 }, SCU4C0, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { D6, D5 }, SCU4A0, BIT_MASK(4) }, ++ /* GPIOI */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { U15, U15 }, SCU4C0, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { U16, U16 }, SCU4C0, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { T17, T17 }, SCU4C0, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P12, P12 }, SCU4C0, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R13, R13 }, SCU4C0, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { T15, T15 }, SCU4C0, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { T16, T16 }, SCU4C0, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R12, R12 }, SCU4C0, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { U15, R12 }, SCU4A0, BIT_MASK(12) }, ++ /* GPIOJ */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { R14, R14 }, SCU4C4, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R17, R17 }, SCU4C4, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R15, R15 }, SCU4C4, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P13, P13 }, SCU4C4, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R16, R16 }, SCU4C4, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P14, P14 }, SCU4C4, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P17, P17 }, SCU4C4, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P16, P16 }, SCU4C4, GENMASK(15, 14) }, ++ /* GPIOK */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { P15, P15 }, SCU4C4, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N17, N17 }, SCU4C4, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N14, N14 }, SCU4C4, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M17, M17 }, SCU4C4, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N15, N15 }, SCU4C4, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N16, N16 }, SCU4C4, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { L17, L17 }, SCU4C4, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { K17, K17 }, SCU4C4, GENMASK(31, 30) }, ++ /* GPIOL */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { J17, J17 }, SCU4C8, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M14, M14 }, SCU4C8, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M15, M15 }, SCU4C8, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M16, M16 }, SCU4C8, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A4, A4 }, SCU4C8, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B5, B5 }, SCU4C8, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A5, A5 }, SCU4C8, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B4, B4 }, SCU4C8, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { J17, B4 }, SCU4A0, BIT_MASK(15) }, ++ /* GPIOM */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { A10, A10 }, SCU4C8, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B9, B9 }, SCU4C8, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C7, C7 }, SCU4C8, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E8, E8 }, SCU4C8, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E7, E7 }, SCU4C8, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B8, B8 }, SCU4C8, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A9, A9 }, SCU4C8, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A8, A8 }, SCU4C8, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { A10, A8 }, SCU4A0, BIT_MASK(16) }, ++ /* GPIOO */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { E13, E13 }, SCU4CC, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C12, C12 }, SCU4CC, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D12, D12 }, SCU4CC, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E12, E12 }, SCU4CC, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D13, D13 }, SCU4CC, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B12, B12 }, SCU4CC, GENMASK(29, 28) }, ++ { PIN_CONFIG_POWER_SOURCE, { E13, B12 }, SCU4A0, BIT_MASK(18) }, ++ /* GPIOP */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D15, D15 }, SCU4D0, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B13, B13 }, SCU4D0, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C14, C14 }, SCU4D0, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C13, C13 }, SCU4D0, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D14, D14 }, SCU4D0, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F13, F13 }, SCU4D0, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E14, E14 }, SCU4D0, GENMASK(13, 12) }, ++ { PIN_CONFIG_POWER_SOURCE, { D15, E14 }, SCU4A0, BIT_MASK(19) }, ++ /* GPIOQ */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { B1, B1 }, SCU4D0, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C2, C2 }, SCU4D0, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D3, D3 }, SCU4D0, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C1, C1 }, SCU4D0, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E5, E5 }, SCU4D0, GENMASK(29, 28) }, ++ /* GPIOS */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { C11, C11 }, SCU4D4, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D11, D11 }, SCU4D4, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C10, C10 }, SCU4D4, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D10, D10 }, SCU4D4, GENMASK(27, 26) }, ++ { PIN_CONFIG_POWER_SOURCE, { C11, D10 }, SCU4A0, BIT_MASK(22) }, ++ /* GPIOT */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D9, D9 }, SCU4D8, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E9, E9 }, SCU4D8, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C9, C9 }, SCU4D8, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D8, D8 }, SCU4D8, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C8, C8 }, SCU4D8, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B11, B11 }, SCU4D8, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { D9, B11 }, SCU4A0, BIT_MASK(23) }, ++ /* GPIOU */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { B10, B10 }, SCU4D8, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A12, A12 }, SCU4D8, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A11, A11 }, SCU4D8, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D7, D7 }, SCU4D8, GENMASK(23, 22) }, ++ { PIN_CONFIG_POWER_SOURCE, { B10, D7 }, SCU4A0, BIT_MASK(24) }, ++ /* GPIOW */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { C4, C4 }, SCU4DC, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A2, A2 }, SCU4DC, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C3, C3 }, SCU4DC, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B2, B2 }, SCU4DC, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B3, B3 }, SCU4DC, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A3, A3 }, SCU4DC, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F2, F2 }, SCU4DC, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F1, F1 }, SCU4DC, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { C4, F1 }, SCU4A0, BIT_MASK(26) }, ++ ++ ASPEED_PULL_DOWN_PINCONF(D6, SCU480, 0), ++ ASPEED_PULL_DOWN_PINCONF(B7, SCU480, 1), ++ ASPEED_PULL_DOWN_PINCONF(A7, SCU480, 2), ++ ASPEED_PULL_DOWN_PINCONF(C6, SCU480, 3), ++ ASPEED_PULL_DOWN_PINCONF(B6, SCU480, 4), ++ ASPEED_PULL_DOWN_PINCONF(A6, SCU480, 5), ++ ASPEED_PULL_DOWN_PINCONF(C5, SCU480, 6), ++ ASPEED_PULL_DOWN_PINCONF(D5, SCU480, 7), ++ ASPEED_PULL_DOWN_PINCONF(L15, SCU480, 8), ++ ASPEED_PULL_DOWN_PINCONF(H17, SCU480, 9), ++ ASPEED_PULL_DOWN_PINCONF(L16, SCU480, 10), ++ ASPEED_PULL_DOWN_PINCONF(K15, SCU480, 11), ++ ASPEED_PULL_DOWN_PINCONF(K16, SCU480, 12), ++ ASPEED_PULL_DOWN_PINCONF(K14, SCU480, 13), ++ ASPEED_PULL_DOWN_PINCONF(J14, SCU480, 14), ++ ASPEED_PULL_DOWN_PINCONF(J16, SCU480, 15), ++ ASPEED_PULL_DOWN_PINCONF(J15, SCU480, 16), ++ ASPEED_PULL_DOWN_PINCONF(G17, SCU480, 17), ++ ASPEED_PULL_DOWN_PINCONF(F17, SCU480, 18), ++ ASPEED_PULL_DOWN_PINCONF(D17, SCU480, 19), ++ ASPEED_PULL_DOWN_PINCONF(C17, SCU480, 20), ++ ASPEED_PULL_DOWN_PINCONF(H16, SCU480, 21), ++ ASPEED_PULL_DOWN_PINCONF(B17, SCU480, 22), ++ ASPEED_PULL_DOWN_PINCONF(E17, SCU480, 23), ++ ASPEED_PULL_DOWN_PINCONF(A16, SCU480, 24), ++ ASPEED_PULL_DOWN_PINCONF(B16, SCU480, 25), ++ ASPEED_PULL_DOWN_PINCONF(H14, SCU480, 26), ++ ASPEED_PULL_DOWN_PINCONF(A15, SCU480, 27), ++ ASPEED_PULL_DOWN_PINCONF(G16, SCU480, 28), ++ ASPEED_PULL_DOWN_PINCONF(F15, SCU480, 29), ++ ASPEED_PULL_DOWN_PINCONF(H15, SCU480, 30), ++ ASPEED_PULL_DOWN_PINCONF(D16, SCU480, 31), ++ ASPEED_PULL_DOWN_PINCONF(M2, SCU484, 0), ++ ASPEED_PULL_DOWN_PINCONF(M1, SCU484, 1), ++ ASPEED_PULL_DOWN_PINCONF(M3, SCU484, 2), ++ ASPEED_PULL_DOWN_PINCONF(M4, SCU484, 3), ++ ASPEED_PULL_DOWN_PINCONF(N1, SCU484, 4), ++ ASPEED_PULL_DOWN_PINCONF(N2, SCU484, 5), ++ ASPEED_PULL_DOWN_PINCONF(N3, SCU484, 6), ++ ASPEED_PULL_DOWN_PINCONF(L5, SCU484, 7), ++ ASPEED_PULL_DOWN_PINCONF(P2, SCU484, 8), ++ ASPEED_PULL_DOWN_PINCONF(P1, SCU484, 9), ++ ASPEED_PULL_DOWN_PINCONF(N4, SCU484, 10), ++ ASPEED_PULL_DOWN_PINCONF(N5, SCU484, 11), ++ ASPEED_PULL_DOWN_PINCONF(HOLE0, SCU484, 12), ++ ASPEED_PULL_DOWN_PINCONF(P3, SCU484, 13), ++ ASPEED_PULL_DOWN_PINCONF(R1, SCU484, 14), ++ ASPEED_PULL_DOWN_PINCONF(P4, SCU484, 15), ++ ASPEED_PULL_DOWN_PINCONF(J2, SCU484, 16), ++ ASPEED_PULL_DOWN_PINCONF(J1, SCU484, 17), ++ ASPEED_PULL_DOWN_PINCONF(K4, SCU484, 18), ++ ASPEED_PULL_DOWN_PINCONF(K2, SCU484, 19), ++ ASPEED_PULL_DOWN_PINCONF(K3, SCU484, 20), ++ ASPEED_PULL_DOWN_PINCONF(K1, SCU484, 21), ++ ASPEED_PULL_DOWN_PINCONF(L4, SCU484, 22), ++ ASPEED_PULL_DOWN_PINCONF(L2, SCU484, 23), ++ ASPEED_PULL_DOWN_PINCONF(L1, SCU484, 24), ++ ASPEED_PULL_DOWN_PINCONF(L3, SCU484, 25), ++ ASPEED_PULL_DOWN_PINCONF(A14, SCU484, 26), ++ ASPEED_PULL_DOWN_PINCONF(B14, SCU484, 27), ++ ASPEED_PULL_DOWN_PINCONF(HOLE1, SCU484, 28), ++ ASPEED_PULL_DOWN_PINCONF(HOLE2, SCU484, 29), ++ ASPEED_PULL_DOWN_PINCONF(HOLE3, SCU484, 30), ++ ASPEED_PULL_DOWN_PINCONF(HOLE4, SCU484, 31), ++ ASPEED_PULL_DOWN_PINCONF(U15, SCU488, 0), ++ ASPEED_PULL_DOWN_PINCONF(U16, SCU488, 1), ++ ASPEED_PULL_DOWN_PINCONF(T17, SCU488, 2), ++ ASPEED_PULL_DOWN_PINCONF(P12, SCU488, 3), ++ ASPEED_PULL_DOWN_PINCONF(R13, SCU488, 4), ++ ASPEED_PULL_DOWN_PINCONF(T15, SCU488, 5), ++ ASPEED_PULL_DOWN_PINCONF(T16, SCU488, 6), ++ ASPEED_PULL_DOWN_PINCONF(R12, SCU488, 7), ++ ASPEED_PULL_DOWN_PINCONF(R14, SCU488, 8), ++ ASPEED_PULL_DOWN_PINCONF(R17, SCU488, 9), ++ ASPEED_PULL_DOWN_PINCONF(R15, SCU488, 10), ++ ASPEED_PULL_DOWN_PINCONF(P13, SCU488, 11), ++ ASPEED_PULL_DOWN_PINCONF(R16, SCU488, 12), ++ ASPEED_PULL_DOWN_PINCONF(P14, SCU488, 13), ++ ASPEED_PULL_DOWN_PINCONF(P17, SCU488, 14), ++ ASPEED_PULL_DOWN_PINCONF(P16, SCU488, 15), ++ ASPEED_PULL_DOWN_PINCONF(P15, SCU488, 16), ++ ASPEED_PULL_DOWN_PINCONF(N17, SCU488, 17), ++ ASPEED_PULL_DOWN_PINCONF(N14, SCU488, 18), ++ ASPEED_PULL_DOWN_PINCONF(M17, SCU488, 19), ++ ASPEED_PULL_DOWN_PINCONF(N15, SCU488, 20), ++ ASPEED_PULL_DOWN_PINCONF(N16, SCU488, 21), ++ ASPEED_PULL_DOWN_PINCONF(L17, SCU488, 22), ++ ASPEED_PULL_DOWN_PINCONF(K17, SCU488, 23), ++ ASPEED_PULL_DOWN_PINCONF(J17, SCU488, 24), ++ ASPEED_PULL_DOWN_PINCONF(M14, SCU488, 25), ++ ASPEED_PULL_DOWN_PINCONF(M15, SCU488, 26), ++ ASPEED_PULL_DOWN_PINCONF(M16, SCU488, 27), ++ ASPEED_PULL_DOWN_PINCONF(A4, SCU488, 28), ++ ASPEED_PULL_DOWN_PINCONF(B5, SCU488, 29), ++ ASPEED_PULL_DOWN_PINCONF(A5, SCU488, 30), ++ ASPEED_PULL_DOWN_PINCONF(B4, SCU488, 31), ++ ASPEED_PULL_DOWN_PINCONF(A10, SCU48C, 0), ++ ASPEED_PULL_DOWN_PINCONF(B9, SCU48C, 1), ++ ASPEED_PULL_DOWN_PINCONF(C7, SCU48C, 2), ++ ASPEED_PULL_DOWN_PINCONF(E8, SCU48C, 3), ++ ASPEED_PULL_DOWN_PINCONF(E7, SCU48C, 4), ++ ASPEED_PULL_DOWN_PINCONF(B8, SCU48C, 5), ++ ASPEED_PULL_DOWN_PINCONF(A9, SCU48C, 6), ++ ASPEED_PULL_DOWN_PINCONF(A8, SCU48C, 7), ++ ASPEED_PULL_DOWN_PINCONF(HOLE5, SCU48C, 8), ++ ASPEED_PULL_DOWN_PINCONF(HOLE6, SCU48C, 9), ++ ASPEED_PULL_DOWN_PINCONF(HOLE7, SCU48C, 10), ++ ASPEED_PULL_DOWN_PINCONF(HOLE8, SCU48C, 11), ++ ASPEED_PULL_DOWN_PINCONF(HOLE9, SCU48C, 12), ++ ASPEED_PULL_DOWN_PINCONF(HOLE10, SCU48C, 13), ++ ASPEED_PULL_DOWN_PINCONF(HOLE11, SCU48C, 14), ++ ASPEED_PULL_DOWN_PINCONF(HOLE12, SCU48C, 15), ++ ASPEED_PULL_DOWN_PINCONF(E13, SCU48C, 16), ++ ASPEED_PULL_DOWN_PINCONF(C12, SCU48C, 17), ++ ASPEED_PULL_DOWN_PINCONF(D12, SCU48C, 18), ++ ASPEED_PULL_DOWN_PINCONF(E12, SCU48C, 19), ++ ASPEED_PULL_DOWN_PINCONF(D13, SCU48C, 20), ++ ASPEED_PULL_DOWN_PINCONF(HOLE13, SCU48C, 21), ++ ASPEED_PULL_DOWN_PINCONF(B12, SCU48C, 22), ++ ASPEED_PULL_DOWN_PINCONF(HOLE14, SCU48C, 23), ++ ASPEED_PULL_DOWN_PINCONF(D15, SCU48C, 24), ++ ASPEED_PULL_DOWN_PINCONF(B13, SCU48C, 25), ++ ASPEED_PULL_DOWN_PINCONF(C14, SCU48C, 26), ++ ASPEED_PULL_DOWN_PINCONF(C13, SCU48C, 27), ++ ASPEED_PULL_DOWN_PINCONF(D14, SCU48C, 28), ++ ASPEED_PULL_DOWN_PINCONF(F13, SCU48C, 29), ++ ASPEED_PULL_DOWN_PINCONF(E14, SCU48C, 30), ++ ASPEED_PULL_DOWN_PINCONF(HOLE15, SCU48C, 31), ++ ASPEED_PULL_DOWN_PINCONF(HOLE16, SCU490, 0), ++ ASPEED_PULL_DOWN_PINCONF(HOLE17, SCU490, 1), ++ ASPEED_PULL_DOWN_PINCONF(B1, SCU490, 2), ++ ASPEED_PULL_DOWN_PINCONF(C2, SCU490, 3), ++ ASPEED_PULL_DOWN_PINCONF(D3, SCU490, 4), ++ ASPEED_PULL_DOWN_PINCONF(C1, SCU490, 5), ++ ASPEED_PULL_DOWN_PINCONF(E5, SCU490, 6), ++ ASPEED_PULL_DOWN_PINCONF(HOLE18, SCU490, 7), ++ ASPEED_PULL_DOWN_PINCONF(HOLE19, SCU490, 8), ++ ASPEED_PULL_DOWN_PINCONF(HOLE20, SCU490, 9), ++ ASPEED_PULL_DOWN_PINCONF(HOLE21, SCU490, 10), ++ ASPEED_PULL_DOWN_PINCONF(HOLE22, SCU490, 11), ++ ASPEED_PULL_DOWN_PINCONF(HOLE23, SCU490, 12), ++ ASPEED_PULL_DOWN_PINCONF(HOLE24, SCU490, 13), ++ ASPEED_PULL_DOWN_PINCONF(HOLE25, SCU490, 14), ++ ASPEED_PULL_DOWN_PINCONF(HOLE26, SCU490, 15), ++ ASPEED_PULL_DOWN_PINCONF(C11, SCU490, 16), ++ ASPEED_PULL_DOWN_PINCONF(D11, SCU490, 17), ++ ASPEED_PULL_DOWN_PINCONF(HOLE27, SCU490, 18), ++ ASPEED_PULL_DOWN_PINCONF(HOLE28, SCU490, 19), ++ ASPEED_PULL_DOWN_PINCONF(C10, SCU490, 20), ++ ASPEED_PULL_DOWN_PINCONF(D10, SCU490, 21), ++ ASPEED_PULL_DOWN_PINCONF(HOLE29, SCU490, 22), ++ ASPEED_PULL_DOWN_PINCONF(HOLE30, SCU490, 23), ++ ASPEED_PULL_DOWN_PINCONF(HOLE31, SCU490, 24), ++ ASPEED_PULL_DOWN_PINCONF(HOLE32, SCU490, 25), ++ ASPEED_PULL_DOWN_PINCONF(D9, SCU490, 26), ++ ASPEED_PULL_DOWN_PINCONF(E9, SCU490, 27), ++ ASPEED_PULL_DOWN_PINCONF(C9, SCU490, 28), ++ ASPEED_PULL_DOWN_PINCONF(D8, SCU490, 29), ++ ASPEED_PULL_DOWN_PINCONF(C8, SCU490, 30), ++ ASPEED_PULL_DOWN_PINCONF(B11, SCU490, 31), ++ ASPEED_PULL_DOWN_PINCONF(B10, SCU494, 0), ++ ASPEED_PULL_DOWN_PINCONF(A12, SCU494, 1), ++ ASPEED_PULL_DOWN_PINCONF(A11, SCU494, 2), ++ ASPEED_PULL_DOWN_PINCONF(D7, SCU494, 3), ++ ASPEED_PULL_DOWN_PINCONF(HOLE33, SCU494, 4), ++ ASPEED_PULL_DOWN_PINCONF(HOLE34, SCU494, 5), ++ ASPEED_PULL_DOWN_PINCONF(HOLE35, SCU494, 6), ++ ASPEED_PULL_DOWN_PINCONF(HOLE36, SCU494, 7), ++ ASPEED_PULL_DOWN_PINCONF(G2, SCU494, 8), ++ ASPEED_PULL_DOWN_PINCONF(G1, SCU494, 9), ++ ASPEED_PULL_DOWN_PINCONF(G4, SCU494, 10), ++ ASPEED_PULL_DOWN_PINCONF(H3, SCU494, 11), ++ ASPEED_PULL_DOWN_PINCONF(H2, SCU494, 12), ++ ASPEED_PULL_DOWN_PINCONF(H1, SCU494, 13), ++ ASPEED_PULL_DOWN_PINCONF(J4, SCU494, 14), ++ ASPEED_PULL_DOWN_PINCONF(J3, SCU494, 15), ++ ASPEED_PULL_DOWN_PINCONF(C4, SCU494, 16), ++ ASPEED_PULL_DOWN_PINCONF(A2, SCU494, 17), ++ ASPEED_PULL_DOWN_PINCONF(C3, SCU494, 18), ++ ASPEED_PULL_DOWN_PINCONF(B2, SCU494, 19), ++ ASPEED_PULL_DOWN_PINCONF(B3, SCU494, 20), ++ ASPEED_PULL_DOWN_PINCONF(A3, SCU494, 21), ++ ASPEED_PULL_DOWN_PINCONF(F2, SCU494, 22), ++ ASPEED_PULL_DOWN_PINCONF(F1, SCU494, 23), ++ ASPEED_PULL_DOWN_PINCONF(D2, SCU494, 24), ++ ASPEED_PULL_DOWN_PINCONF(D1, SCU494, 25), ++ ASPEED_PULL_DOWN_PINCONF(F4, SCU494, 26), ++ ASPEED_PULL_DOWN_PINCONF(E4, SCU494, 27), ++ ASPEED_PULL_DOWN_PINCONF(E2, SCU494, 28), ++ ASPEED_PULL_DOWN_PINCONF(E1, SCU494, 29), ++ ASPEED_PULL_DOWN_PINCONF(F3, SCU494, 30), ++ ASPEED_PULL_DOWN_PINCONF(G5, SCU494, 31), ++ ASPEED_PULL_DOWN_PINCONF(T4, SCU498, 0), ++ ASPEED_PULL_DOWN_PINCONF(T3, SCU498, 1), ++ ASPEED_PULL_DOWN_PINCONF(R5, SCU498, 2), ++ ASPEED_PULL_DOWN_PINCONF(R6, SCU498, 3), ++ ASPEED_PULL_DOWN_PINCONF(T2, SCU498, 4), ++ ASPEED_PULL_DOWN_PINCONF(T5, SCU498, 5), ++ ASPEED_PULL_DOWN_PINCONF(U2, SCU498, 6), ++ ASPEED_PULL_DOWN_PINCONF(R7, SCU498, 7), ++ ASPEED_PULL_DOWN_PINCONF(P9, SCU498, 8), ++ ASPEED_PULL_DOWN_PINCONF(U4, SCU498, 9), ++ ASPEED_PULL_DOWN_PINCONF(U5, SCU498, 10), ++ ASPEED_PULL_DOWN_PINCONF(U6, SCU498, 11), ++ ASPEED_PULL_DOWN_PINCONF(T7, SCU498, 12), ++ ASPEED_PULL_DOWN_PINCONF(U7, SCU498, 13), ++ ASPEED_PULL_DOWN_PINCONF(R10, SCU498, 14), ++ ASPEED_PULL_DOWN_PINCONF(R11, SCU498, 15), ++ ASPEED_PULL_DOWN_PINCONF(C16, SCU498, 16), ++ ASPEED_PULL_DOWN_PINCONF(F16, SCU498, 17), ++ ASPEED_PULL_DOWN_PINCONF(B15, SCU498, 18), ++ ASPEED_PULL_DOWN_PINCONF(G15, SCU498, 19), ++ ASPEED_PULL_DOWN_PINCONF(G14, SCU498, 20), ++ ASPEED_PULL_DOWN_PINCONF(F14, SCU498, 21), ++ ASPEED_PULL_DOWN_PINCONF(E15, SCU498, 22), ++ ASPEED_PULL_DOWN_PINCONF(C15, SCU498, 23), ++}; ++ ++static const struct aspeed_pin_config_map aspeed_g7_ltpi_pin_config_map[] = { ++ { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0) }, ++ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0) }, ++ { PIN_CONFIG_BIAS_PULL_UP, 0, 1, BIT_MASK(0) }, ++ { PIN_CONFIG_BIAS_PULL_UP, -1, 0, BIT_MASK(0) }, ++ { PIN_CONFIG_BIAS_DISABLE, -1, 1, BIT_MASK(0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 0, 0, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 1, 1, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 2, 2, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 3, 3, GENMASK(1, 0) }, ++ { PIN_CONFIG_POWER_SOURCE, 3300, 0, BIT_MASK(0) }, ++ { PIN_CONFIG_POWER_SOURCE, 1800, 1, BIT_MASK(0) }, ++}; ++ +static int aspeed_g7_ltpi_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, u32 *num_maps) @@ -51726,6 +52152,10 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a + ltpi_pinctrl_data->pinmux.nfunctions = ARRAY_SIZE(aspeed_g7_ltpi_funcs); + ltpi_pinctrl_data->pinmux.configs_g7 = pin_cfg; + ltpi_pinctrl_data->pinmux.nconfigs_g7 = ARRAY_SIZE(pin_cfg); ++ ltpi_pinctrl_data->configs = aspeed_g7_ltpi_configs; ++ ltpi_pinctrl_data->nconfigs = ARRAY_SIZE(aspeed_g7_ltpi_configs); ++ ltpi_pinctrl_data->confmaps = aspeed_g7_ltpi_pin_config_map; ++ ltpi_pinctrl_data->nconfmaps = ARRAY_SIZE(aspeed_g7_ltpi_pin_config_map); + + return aspeed_pinctrl_probe(pdev, &aspeed_g7_ltpi_pinctrl_desc, ltpi_pinctrl_data); +} @@ -51752,7 +52182,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-ltpi.c b/drivers/pinctrl/a +arch_initcall(aspeed_g7_ltpi_pinctrl_register); diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c 2025-12-23 10:16:21.136032468 +0000 ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c 2026-09-09 15:51:44.732237860 +0000 @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 + @@ -52259,8 +52689,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c b/drivers/pinctrl/a +arch_initcall(aspeed_g7_soc0_pinctrl_register); diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c 2025-12-23 10:16:21.136032468 +0000 -@@ -0,0 +1,2533 @@ ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c 2026-09-09 15:51:44.732237860 +0000 +@@ -0,0 +1,2537 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include @@ -52780,7 +53210,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +GROUP_DECL(SPI2CS1, A26); +GROUP_DECL(THRU2, A19, A18); +GROUP_DECL(THRU3, B25, F26); -+GROUP_DECL(JTAGM1, D12, F10, E11, F11, F13); ++GROUP_DECL(JTAGM1, F10, E11, F11, F13); ++GROUP_DECL(JTAGM1TRST, D12); +GROUP_DECL(MDIO0, B9, M14); +GROUP_DECL(MDIO1, C9, C10); +GROUP_DECL(MDIO2, E10, E13); @@ -52799,7 +53230,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +GROUP_DECL(I2CF0, F12, E12, J12, G7); +GROUP_DECL(I2CF1, E9, F9, F8, M13); +GROUP_DECL(I2CF2, F7, D8, E8, L12); -+GROUP_DECL(CANBUS, G7, G8, G9); ++GROUP_DECL(CANBUS, G8, G9); ++GROUP_DECL(CANBUSSTBY, G7); +GROUP_DECL(USBUART, G10, K12); +GROUP_DECL(HBLED, V24); +GROUP_DECL(MACLINK0, U21); @@ -53057,6 +53489,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a + ASPEED_PINCTRL_GROUP(THRU2), + ASPEED_PINCTRL_GROUP(THRU3), + ASPEED_PINCTRL_GROUP(JTAGM1), ++ ASPEED_PINCTRL_GROUP(JTAGM1TRST), + ASPEED_PINCTRL_GROUP(MDIO0), + ASPEED_PINCTRL_GROUP(MDIO1), + ASPEED_PINCTRL_GROUP(MDIO2), @@ -53076,6 +53509,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a + ASPEED_PINCTRL_GROUP(I2CF1), + ASPEED_PINCTRL_GROUP(I2CF2), + ASPEED_PINCTRL_GROUP(CANBUS), ++ ASPEED_PINCTRL_GROUP(CANBUSSTBY), + ASPEED_PINCTRL_GROUP(USBUART), + ASPEED_PINCTRL_GROUP(HBLED), + ASPEED_PINCTRL_GROUP(MACLINK0), @@ -53273,7 +53707,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +FUNC_DECL_(SPI2CS1, "SPI2CS1"); +FUNC_DECL_(THRU2, "THRU2"); +FUNC_DECL_(THRU3, "THRU3"); -+FUNC_DECL_(JTAGM1, "JTAGM1"); ++FUNC_DECL_(JTAGM1, "JTAGM1", "JTAGM1TRST"); +FUNC_DECL_(MDIO0, "MDIO0"); +FUNC_DECL_(MDIO1, "MDIO1"); +FUNC_DECL_(MDIO2, "MDIO2"); @@ -53291,7 +53725,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +FUNC_DECL_(I2CF0, "I2CF0"); +FUNC_DECL_(I2CF1, "I2CF1"); +FUNC_DECL_(I2CF2, "I2CF2"); -+FUNC_DECL_(CANBUS, "CANBUS"); ++FUNC_DECL_(CANBUS, "CANBUS", "CANBUSSTBY"); +FUNC_DECL_(USBUART, "USBUART"); +FUNC_DECL_(HBLED, "HBLED"); +FUNC_DECL_(MACLINK0, "MACLINK0"); @@ -54049,7 +54483,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +FUNCFG_DESCL(E10, PIN_CFG(MDIO2, SCU440, GENMASK(2, 0), 1), + PIN_CFG(PE2SGRSTN, SCU440, GENMASK(2, 0), 2)); +FUNCFG_DESCL(E13, PIN_CFG(MDIO2, SCU440, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(D12, PIN_CFG(JTAGM1, SCU440, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(D12, PIN_CFG(JTAGM1TRST, SCU440, GENMASK(10, 8), (1 << 8))); +FUNCFG_DESCL(F10, PIN_CFG(JTAGM1, SCU440, GENMASK(14, 12), (1 << 12))); +FUNCFG_DESCL(E11, PIN_CFG(JTAGM1, SCU440, GENMASK(18, 16), (1 << 16))); +FUNCFG_DESCL(F11, PIN_CFG(JTAGM1, SCU440, GENMASK(22, 20), (1 << 20))); @@ -54154,7 +54588,7 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +FUNCFG_DESCL(J12, PIN_CFG(I2C9, SCU45C, GENMASK(10, 8), (1 << 8)), + PIN_CFG(I2CF0, SCU45C, GENMASK(10, 8), (5 << 8))); +FUNCFG_DESCL(G7, PIN_CFG(I2C9, SCU45C, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(CANBUS, SCU45C, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(CANBUSSTBY, SCU45C, GENMASK(14, 12), (2 << 12)), + PIN_CFG(I2CF0, SCU45C, GENMASK(14, 12), (5 << 12))); +FUNCFG_DESCL(G8, PIN_CFG(I2C10, SCU45C, GENMASK(18, 16), (1 << 16)), + PIN_CFG(CANBUS, SCU45C, GENMASK(18, 16), (2 << 16))); @@ -54795,8 +55229,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/a +} +arch_initcall(aspeed_g7_soc1_pinctrl_register); diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c ---- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c 2025-12-23 10:16:21.136032468 +0000 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c 2026-09-09 15:51:44.733237845 +0000 @@ -285,6 +285,32 @@ return 0; } @@ -54859,8 +55293,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pi struct pinctrl_desc *pdesc, struct aspeed_pinctrl_data *pdata) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h ---- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h 2025-12-23 10:16:21.136032468 +0000 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h 2026-09-09 15:51:44.733237845 +0000 @@ -70,15 +70,15 @@ struct regmap *scu; @@ -54893,8 +55327,8 @@ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pi struct pinctrl_desc *pdesc, struct aspeed_pinctrl_data *pdata); diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pinmux-aspeed.h ---- a/drivers/pinctrl/aspeed/pinmux-aspeed.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pinctrl/aspeed/pinmux-aspeed.h 2025-12-23 10:16:21.136032468 +0000 +--- a/drivers/pinctrl/aspeed/pinmux-aspeed.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pinctrl/aspeed/pinmux-aspeed.h 2026-09-09 15:51:44.733237845 +0000 @@ -792,6 +792,33 @@ const struct aspeed_sig_expr *expr, bool enabled); }; @@ -54946,60 +55380,9 @@ diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pin }; int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled, -diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c ---- a/drivers/pwm/core.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pwm/core.c 2025-12-23 10:16:22.024017585 +0000 -@@ -426,9 +426,8 @@ - * chip. A negative error code is returned if the index is not valid for the - * specified PWM chip or if the PWM device cannot be requested. - */ --static struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, -- unsigned int index, -- const char *label) -+struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, -+ unsigned int index, const char *label) - { - struct pwm_device *pwm; - int err; -@@ -446,6 +445,7 @@ - - return pwm; - } -+EXPORT_SYMBOL_GPL(pwm_request_from_chip); - - struct pwm_device * - of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args) -diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig ---- a/drivers/reset/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/reset/Kconfig 2025-12-23 10:16:09.724223772 +0000 -@@ -22,6 +22,13 @@ - This option enables support for the external reset functions for - peripheral PHYs on the Altera Arria10 System Resource Chip. - -+config RESET_ASPEED -+ tristate "ASPEED Reset Driver" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ select AUXILIARY_BUS -+ help -+ This enables the reset controller driver for AST2700. -+ - config RESET_ATH79 - bool "AR71xx Reset Driver" if COMPILE_TEST - default ATH79 -diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile ---- a/drivers/reset/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/reset/Makefile 2025-12-23 10:16:13.896153811 +0000 -@@ -5,6 +5,7 @@ - obj-y += sti/ - obj-y += tegra/ - obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o -+obj-$(CONFIG_RESET_ASPEED) += reset-aspeed.o - obj-$(CONFIG_RESET_ATH79) += reset-ath79.o - obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o - obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o diff --git a/drivers/reset/reset-aspeed.c b/drivers/reset/reset-aspeed.c --- a/drivers/reset/reset-aspeed.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/reset/reset-aspeed.c 2025-12-23 10:16:21.120032737 +0000 ++++ b/drivers/reset/reset-aspeed.c 2026-09-09 15:51:44.708238223 +0000 @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* @@ -55312,8 +55695,8 @@ diff --git a/drivers/reset/reset-aspeed.c b/drivers/reset/reset-aspeed.c +MODULE_DESCRIPTION("ASPEED SoC Reset Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c ---- a/drivers/rtc/rtc-aspeed.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/rtc/rtc-aspeed.c 2025-12-23 10:16:21.094033172 +0000 +--- a/drivers/rtc/rtc-aspeed.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/rtc/rtc-aspeed.c 2026-09-09 15:51:44.679238661 +0000 @@ -10,14 +10,64 @@ struct aspeed_rtc { struct rtc_device *rtc_dev; @@ -55399,7 +55782,7 @@ diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c cent = (tm->tm_year + 1900) / 100; year = tm->tm_year % 100; -@@ -77,40 +129,211 @@ +@@ -77,40 +129,215 @@ return 0; } @@ -55579,21 +55962,25 @@ diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c + * In rtc_read_time, run aspeed_rtc_read_time and check the rtc_time. + * As a result, need to enable and initialize RTC time. + * ++ * If the RTC_ENABLE has been set, it means that the RTC has been initialed + * Enable and unlock RTC to initialize RTC time to 1970-01-01T01:01:01 + * and re-lock and ensure enable is set now that a time is programmed. + */ + ctrl = readl(rtc->base + RTC_CTRL); -+ writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL); + -+ /* -+ * Initial value set to year:70,mon:0,mday:1,hour:1,min:1,sec:1 -+ * rtc_valid_tm check whether in suitable range or not. -+ */ -+ writel(0x01010101, rtc->base + RTC_TIME); -+ writel(0x00134601, rtc->base + RTC_YEAR); ++ if (!(ctrl & RTC_ENABLE)) { ++ writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL); + -+ /* Re-lock and ensure enable is set now that a time is programmed */ -+ writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL); ++ /* ++ * Initial value set to year:70,mon:0,mday:1,hour:1,min:1,sec:1 ++ * rtc_valid_tm check whether in suitable range or not. ++ */ ++ writel(0x01010101, rtc->base + RTC_TIME); ++ writel(0x00134601, rtc->base + RTC_YEAR); ++ ++ /* Re-lock and ensure enable is set now that a time is programmed */ ++ writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL); ++ } + + rc = devm_rtc_register_device(rtc->rtc_dev); + if (rc) { @@ -55616,8 +56003,8 @@ diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c }; MODULE_DEVICE_TABLE(of, aspeed_rtc_match); diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig ---- a/drivers/soc/aspeed/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/Kconfig 2025-12-23 10:16:21.124032669 +0000 +--- a/drivers/soc/aspeed/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/soc/aspeed/Kconfig 2026-09-09 15:51:44.717238087 +0000 @@ -4,6 +4,12 @@ menu "ASPEED SoC drivers" @@ -55662,17 +56049,16 @@ diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig config ASPEED_P2A_CTRL tristate "ASPEED P2A (VGA MMIO to BMC) bridge control" select REGMAP -@@ -52,6 +75,134 @@ +@@ -52,6 +75,98 @@ help Say yes to support decoding of ASPEED BMC information. +config ASPEED_SBC + bool "ASPEED Secure Boot Controller driver" -+ depends on ARM + default MACH_ASPEED_G6 + help + Say yes to provide information about the secure boot controller in -+ debugfs. This is only for AST2600 (ARM32). ++ debugfs. + +config ASPEED_XDMA + tristate "ASPEED XDMA Engine Driver" @@ -55732,44 +56118,6 @@ diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig + SOCs. The UDMA engine can perform UART DMA operations between the memory + buffer and the UART/VUART devices. + -+config ASPEED_PCIE_MMBI -+ tristate "ASPEED PCIE MMBI" -+ -+config ASPEED_ESPI -+ tristate "ASPEED eSPI slave driver" -+ select AST2500_ESPI if MACH_ASPEED_G5 -+ select AST2600_ESPI if MACH_ASPEED_G6 -+ default n -+ -+config AST2500_ESPI -+ tristate -+ depends on ASPEED_ESPI -+ help -+ Enable driver support for Aspeed AST2500 eSPI engine. -+ -+config AST2600_ESPI -+ tristate "ASPEED AST2600 eSPI slave driver" -+ help -+ Enable driver support for Aspeed AST2600 eSPI engine. The eSPI engine -+ plays as a slave device in BMC to communicate with the Host over -+ the eSPI interface. The four eSPI channels, namely peripheral, -+ virtual wire, out-of-band, and flash are supported. -+ -+config AST2700_ESPI -+ tristate "ASPEED AST2700 eSPI slave driver" -+ help -+ Enable driver support for Aspeed AST2700 eSPI engine. The eSPI engine -+ plays as a slave device in BMC to communicate with the Host over -+ the eSPI interface. The four eSPI channels, namely peripheral, -+ virtual wire, out-of-band, and flash are supported. -+ -+config AST2700_RTC_OVER_ESPI -+ tristate "ASPEED AST2700 RTC over eSPI drvier" -+ depends on HAS_IOMEM -+ help -+ Enable driver support for Aspeed AST2700 RTC over eSPI function. -+ Periodically copies RAM content from a RTC tm to a memory-mapped eSPI region. -+ +config ASPEED_OTP + tristate + help @@ -55792,15 +56140,18 @@ diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig + help + Enable driver support for Aspeed AST2700 OTP driver. + ++source "drivers/soc/aspeed/espi/Kconfig" +source "drivers/soc/aspeed/rvas/Kconfig" ++ ++source "drivers/soc/aspeed/mmbi/Kconfig" + endmenu endif diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile ---- a/drivers/soc/aspeed/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/Makefile 2025-12-23 10:16:21.183031681 +0000 -@@ -1,6 +1,26 @@ +--- a/drivers/soc/aspeed/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/soc/aspeed/Makefile 2026-09-09 15:51:44.771237271 +0000 +@@ -1,6 +1,23 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_ASPEED_BMC_DEV) += aspeed-bmc-dev.o +obj-$(CONFIG_ASPEED_HOST_BMC_DEV) += aspeed-host-bmc-dev.o @@ -55814,23 +56165,20 @@ diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o +obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o -+obj-$(CONFIG_AST2500_ESPI) += ast2500-espi.o -+obj-$(CONFIG_AST2600_ESPI) += ast2600-espi.o -+obj-$(CONFIG_AST2700_ESPI) += ast2700-espi.o +obj-$(CONFIG_ASPEED_RVAS) += rvas/ +obj-$(CONFIG_ARCH_ASPEED) += aspeed-usb-phy.o +obj-$(CONFIG_ARCH_ASPEED) += aspeed-usb-hp.o +obj-$(CONFIG_ASPEED_MCTP) += aspeed-mctp.o +obj-$(CONFIG_ASPEED_DISP_INTF) += aspeed-disp-intf.o -+obj-$(CONFIG_ASPEED_PCIE_MMBI) += aspeed-pcie-mmbi.o +obj-$(CONFIG_ASPEED_MBOX) += aspeed-mbox.o -+obj-$(CONFIG_AST2700_RTC_OVER_ESPI) += ast2700-rtc-over-espi.o +obj-$(CONFIG_AST2600_OTP) += ast2600-otp.o +obj-$(CONFIG_AST2700_OTP) += ast2700-otp.o ++obj-y += espi/ ++obj-y += mmbi/ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc-dev.c --- a/drivers/soc/aspeed/aspeed-bmc-dev.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-bmc-dev.c 2025-12-23 10:16:21.124032669 +0000 -@@ -0,0 +1,699 @@ ++++ b/drivers/soc/aspeed/aspeed-bmc-dev.c 2026-09-09 15:51:44.718238072 +0000 +@@ -0,0 +1,701 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) ASPEED Technology Inc. + @@ -55953,6 +56301,7 @@ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc + void __iomem *reg_base; + dma_addr_t bmc_mem_phy; + phys_addr_t bmc_mem_size; ++ void *bmc_mem_cpu; + + int pcie2lpc; + int irq; @@ -55979,18 +56328,15 @@ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc +{ + struct aspeed_bmc_device *bmc_device = file_aspeed_bmc_device(file); + unsigned long vsize = vma->vm_end - vma->vm_start; -+ pgprot_t prot = vma->vm_page_prot; + -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vsize) > bmc_device->bmc_mem_size) ++ if (vsize > bmc_device->bmc_mem_size) + return -EINVAL; + -+ prot = pgprot_noncached(prot); -+ -+ if (remap_pfn_range(vma, vma->vm_start, -+ (bmc_device->bmc_mem_phy >> PAGE_SHIFT) + vma->vm_pgoff, vsize, prot)) -+ return -EAGAIN; ++ return dma_mmap_coherent(bmc_device->dev, vma, ++ bmc_device->bmc_mem_cpu, ++ bmc_device->bmc_mem_phy, ++ bmc_device->bmc_mem_size); + -+ return 0; +} + +static const struct file_operations aspeed_bmc_device_fops = { @@ -56414,42 +56760,53 @@ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc + bmc_device->dev = dev; + bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(bmc_device->reg_base)) -+ goto out_region; ++ return PTR_ERR(bmc_device->reg_base); ++ ++ ret = of_reserved_mem_device_init(dev); ++ if (ret) { ++ dev_err(dev, "of_reserved_mem_device_init failed: %d\n", ret); ++ return ret; ++ } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ goto out_region; ++ return ret; + } + + np = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!np || of_address_to_resource(np, 0, &res)) { + dev_err(dev, "Failed to find memory-region.\n"); -+ ret = -ENOMEM; -+ goto out_region; ++ return -ENOMEM; + } + + of_node_put(np); + -+ bmc_device->bmc_mem_phy = res.start; + bmc_device->bmc_mem_size = resource_size(&res); ++ bmc_device->bmc_mem_cpu = dmam_alloc_coherent(dev, bmc_device->bmc_mem_size, ++ &bmc_device->bmc_mem_phy, GFP_KERNEL); ++ if (!bmc_device->bmc_mem_cpu) { ++ dev_err(dev, "Failed to allocate BMC memory.\n"); ++ return -ENOMEM; ++ } + + bmc_device->irq = platform_get_irq(pdev, 0); + if (bmc_device->irq < 0) { + dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", bmc_device->irq); -+ goto out_unmap; ++ return bmc_device->irq; + } ++ + ret = devm_request_irq(&pdev->dev, bmc_device->irq, aspeed_bmc_dev_isr, 0, + dev_name(&pdev->dev), bmc_device); + if (ret) { + dev_err(dev, "aspeed bmc device Unable to get IRQ"); -+ goto out_unmap; ++ return ret; + } + + ret = aspeed_bmc_device_setup_queue(pdev); + if (ret) { + dev_err(dev, "Cannot setup queue message"); -+ goto out_irq; ++ goto out; + } + + ret = aspeed_bmc_device_setup_memory_mapping(pdev); @@ -56490,12 +56847,7 @@ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc +out_free_queue: + for (i = 0; i < ASPEED_QUEUE_NUM; i++) + sysfs_remove_bin_file(&pdev->dev.kobj, &bmc_device->queue[i].bin); -+out_irq: -+ devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device); -+out_unmap: -+ iounmap(bmc_device->reg_base); -+out_region: -+ devm_kfree(&pdev->dev, bmc_device); ++out: + dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret); + return ret; +} @@ -56511,8 +56863,6 @@ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc + devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device); + devm_free_irq(&pdev->dev, bmc_device->pcie_irq, bmc_device); + -+ iounmap(bmc_device->reg_base); -+ + devm_kfree(&pdev->dev, bmc_device); +} + @@ -56532,7 +56882,7 @@ diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/aspeed/aspeed-disp-intf.c b/drivers/soc/aspeed/aspeed-disp-intf.c --- a/drivers/soc/aspeed/aspeed-disp-intf.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-disp-intf.c 2025-12-23 10:16:21.124032669 +0000 ++++ b/drivers/soc/aspeed/aspeed-disp-intf.c 2026-09-09 15:51:44.718238072 +0000 @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) ASPEED Technology Inc. @@ -56789,220 +57139,10 @@ diff --git a/drivers/soc/aspeed/aspeed-disp-intf.c b/drivers/soc/aspeed/aspeed-d +MODULE_AUTHOR("Jammy Huang "); +MODULE_DESCRIPTION("ASPEED Display Interface Driver"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/aspeed-espi-comm.h b/drivers/soc/aspeed/aspeed-espi-comm.h ---- a/drivers/soc/aspeed/aspeed-espi-comm.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-espi-comm.h 2025-12-23 10:16:21.124032669 +0000 -@@ -0,0 +1,206 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#ifndef __ASPEED_ESPI_COMM_H__ -+#define __ASPEED_ESPI_COMM_H__ -+ -+#include -+#include -+ -+/* -+ * eSPI cycle type encoding -+ * -+ * Section 5.1 Cycle Types and Packet Format, -+ * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. -+ */ -+#define ESPI_PERIF_MEMRD32 0x00 -+#define ESPI_PERIF_MEMRD64 0x02 -+#define ESPI_PERIF_MEMWR32 0x01 -+#define ESPI_PERIF_MEMWR64 0x03 -+#define ESPI_PERIF_MSG 0x10 -+#define ESPI_PERIF_MSG_D 0x11 -+#define ESPI_PERIF_SUC_CMPLT 0x06 -+#define ESPI_PERIF_SUC_CMPLT_D_MIDDLE 0x09 -+#define ESPI_PERIF_SUC_CMPLT_D_FIRST 0x0b -+#define ESPI_PERIF_SUC_CMPLT_D_LAST 0x0d -+#define ESPI_PERIF_SUC_CMPLT_D_ONLY 0x0f -+#define ESPI_PERIF_UNSUC_CMPLT 0x0c -+#define ESPI_OOB_MSG 0x21 -+#define ESPI_FLASH_READ 0x00 -+#define ESPI_FLASH_WRITE 0x01 -+#define ESPI_FLASH_ERASE 0x02 -+#define ESPI_FLASH_SUC_CMPLT 0x06 -+#define ESPI_FLASH_SUC_CMPLT_D_MIDDLE 0x09 -+#define ESPI_FLASH_SUC_CMPLT_D_FIRST 0x0b -+#define ESPI_FLASH_SUC_CMPLT_D_LAST 0x0d -+#define ESPI_FLASH_SUC_CMPLT_D_ONLY 0x0f -+#define ESPI_FLASH_UNSUC_CMPLT 0x0c -+ -+/* -+ * eSPI packet format structure -+ * -+ * Section 5.1 Cycle Types and Packet Format, -+ * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. -+ */ -+struct espi_comm_hdr { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+}; -+ -+struct espi_perif_mem32 { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint32_t addr_be; -+ uint8_t data[]; -+} __packed; -+ -+struct espi_perif_mem64 { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint32_t addr_be; -+ uint8_t data[]; -+} __packed; -+ -+struct espi_perif_msg { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint8_t msg_code; -+ uint8_t msg_byte[4]; -+ uint8_t data[]; -+} __packed; -+ -+struct espi_perif_cmplt { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint8_t data[]; -+} __packed; -+ -+struct espi_oob_msg { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint8_t data[]; -+}; -+ -+struct espi_flash_rwe { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint32_t addr_be; -+ uint8_t data[]; -+} __packed; -+ -+struct espi_flash_cmplt { -+ uint8_t cyc; -+ uint8_t len_h : 4; -+ uint8_t tag : 4; -+ uint8_t len_l; -+ uint8_t data[]; -+} __packed; -+ -+#define ESPI_MAX_PLD_LEN BIT(12) -+ -+/* -+ * Aspeed IOCTL for eSPI raw packet send/receive -+ * -+ * This IOCTL interface works in the eSPI packet in/out paradigm. -+ * -+ * Only the virtual wire IOCTL is a special case which does not send -+ * or receive an eSPI packet. However, to keep a more consisten use from -+ * userspace, we make all of the four channel drivers serve through the -+ * IOCTL interface. -+ * -+ * For the eSPI packet format, refer to -+ * Section 5.1 Cycle Types and Packet Format, -+ * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. -+ * -+ * For the example user apps using these IOCTL, refer to -+ * https://github.com/AspeedTech-BMC/aspeed_app/tree/master/espi_test -+ */ -+#define __ASPEED_ESPI_IOCTL_MAGIC 0xb8 -+ -+/* -+ * we choose the longest header and the max payload size -+ * based on the Intel specification to define the maximum -+ * eSPI packet length -+ */ -+#define ESPI_MAX_PKT_LEN (sizeof(struct espi_perif_msg) + ESPI_MAX_PLD_LEN) -+ -+struct aspeed_espi_ioc { -+ uint32_t pkt_len; -+ uint8_t *pkt; -+}; -+ -+/* -+ * Peripheral Channel (CH0) -+ * - ASPEED_ESPI_PERIF_PC_GET_RX -+ * Receive an eSPI Posted/Completion packet -+ * - ASPEED_ESPI_PERIF_PC_PUT_TX -+ * Transmit an eSPI Posted/Completion packet -+ * - ASPEED_ESPI_PERIF_NP_PUT_TX -+ * Transmit an eSPI Non-Posted packet -+ */ -+#define ASPEED_ESPI_PERIF_PC_GET_RX _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x00, struct aspeed_espi_ioc) -+#define ASPEED_ESPI_PERIF_PC_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x01, struct aspeed_espi_ioc) -+#define ASPEED_ESPI_PERIF_NP_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x02, struct aspeed_espi_ioc) -+/* -+ * Virtual Wire Channel (CH1) -+ * - ASPEED_ESPI_VW_GET_GPIO_VAL -+ * Read the input value of GPIO over the VW channel -+ * - ASPEED_ESPI_VW_PUT_GPIO_VAL -+ * Write the output value of GPIO over the VW channel -+ * - ASPEED_ESPI_VW_GET_GPIO_VAL1 (new feature in AST2700) -+ * Read the input value1 of GPIO over the VW channel -+ * - ASPEED_ESPI_VW_PUT_GPIO_VAL1 (new feature in AST2700) -+ * Write the output value1 of GPIO over the VW channel -+ */ -+#define ASPEED_ESPI_VW_GET_GPIO_VAL _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x10, uint32_t) -+#define ASPEED_ESPI_VW_PUT_GPIO_VAL _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x11, uint32_t) -+#ifdef CONFIG_ARM64 -+#define ASPEED_ESPI_VW_GET_GPIO_VAL1 _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x12, uint32_t) -+#define ASPEED_ESPI_VW_PUT_GPIO_VAL1 _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x13, uint32_t) -+#endif -+/* -+ * Out-of-band Channel (CH2) -+ * - ASPEED_ESPI_OOB_GET_RX -+ * Receive an eSPI OOB packet -+ * - ASPEED_ESPI_OOB_PUT_TX -+ * Transmit an eSPI OOB packet -+ */ -+#define ASPEED_ESPI_OOB_GET_RX _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x20, struct aspeed_espi_ioc) -+#define ASPEED_ESPI_OOB_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x21, struct aspeed_espi_ioc) -+/* -+ * Flash Channel (CH3) -+ * - ASPEED_ESPI_FLASH_GET_RX -+ * Receive an eSPI flash packet -+ * - ASPEED_ESPI_FLASH_PUT_TX -+ * Transmit an eSPI flash packet -+ */ -+#define ASPEED_ESPI_FLASH_GET_RX _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x30, struct aspeed_espi_ioc) -+#define ASPEED_ESPI_FLASH_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -+ 0x31, struct aspeed_espi_ioc) -+ -+#endif diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspeed-host-bmc-dev.c --- a/drivers/soc/aspeed/aspeed-host-bmc-dev.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-host-bmc-dev.c 2025-12-23 10:16:21.124032669 +0000 -@@ -0,0 +1,1435 @@ ++++ b/drivers/soc/aspeed/aspeed-host-bmc-dev.c 2026-09-09 15:51:44.718238072 +0000 +@@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) ASPEED Technology Inc. + @@ -57029,8 +57169,9 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee +#include +#include +#include -+ -+#include "aspeed-pcie-mmbi.h" ++#if IS_ENABLED(CONFIG_ASPEED_MMBI) ++#include "mmbi/aspeed-mmbi.h" ++#endif + +#define PCI_BMC_HOST2BMC_Q1 0x30000 +#define PCI_BMC_HOST2BMC_Q2 0x30010 @@ -57064,16 +57205,10 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + +static DEFINE_IDA(bmc_device_ida); + -+#define MMBI_MAX_INST 6 +#define VUART_MAX_PARMS 2 +#define ASPEED_QUEUE_NUM 2 +#define MAX_MSI_NUM 8 + -+enum aspeed_platform_id { -+ ASPEED, -+ ASPEED_AST2700_SOC1, -+}; -+ +enum queue_index { + QUEUE1 = 0, + QUEUE2, @@ -57084,17 +57219,11 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + MBX_MSI, + VUART0_MSI, + VUART1_MSI, -+ MMBI0_MSI, -+ MMBI1_MSI, -+ MMBI2_MSI, -+ MMBI3_MSI, +}; + +/* Match msi_index */ +static int ast2600_msi_idx_table[MAX_MSI_NUM] = { 4, 21, 16, 15 }; -+static int ast2700_soc0_msi_idx_table[MAX_MSI_NUM] = { 0, 11, 6, 5, 28, 29, 30, 31 }; -+/* ARRAY = MMIB0_MSI, MMBI1_MSI, MMBI2_MSI, MMBI3_MSI, MMBI4_MSI, MMBI5_MSI */ -+static int ast2700_soc1_msi_idx_table[MAX_MSI_NUM] = { 1, 2, 3, 4, 5, 6 }; ++static int ast2700_soc0_msi_idx_table[MAX_MSI_NUM] = { 0, 11, 6, 5}; + +struct aspeed_platform { + int (*setup)(struct pci_dev *pdev); @@ -57110,17 +57239,47 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + struct aspeed_pci_bmc_dev *pci_bmc_device; +}; + -+struct aspeed_pcie_mmbi { -+ resource_size_t base; -+ resource_size_t mem_size; -+ void __iomem *mem; -+ u32 segment_size; ++#if IS_ENABLED(CONFIG_ASPEED_MMBI) ++struct aspeed_host_pcie_mmbi_ins { ++ struct mmbi_ins_desc mmbi_desc; + int irq; -+ int id; -+ struct aspeed_mmbi_channel chan; ++ int msi_index; ++ int instance_index; ++ int bar_index; + const char *dev_name; ++ bool valid; ++}; ++ ++struct aspeed_host_pcie_mmbi { ++ struct device *dev; ++ struct aspeed_host_pcie_mmbi_ins instances[PCI_STD_NUM_BARS]; ++ int msi_nums; +}; + ++/* ++ * app_interface: per-channel application interface selection. ++ * 0 = ioctl (MMBI_APP_INTF_IOCTL) ++ * 1 = mctp-netdev (MMBI_APP_INTF_MCTP_NETDEV) ++ * ++ * One value applies to every channel. Multiple values map by channel index, ++ * and omitted channels keep their defaults. ++ * Examples: ++ * app_interface=1 -> all channels use mctp-netdev ++ * app_interface=1,0,0,0,1 -> ch0/ch4 use mctp-netdev ++ * Invalid values fall back to the default map. ++ */ ++static const uint app_interface_defaults[MMBI_MAX_CHANNELS] = { ++ [0] = MMBI_APP_INTF_MCTP_NETDEV, ++}; ++ ++static uint app_interface[MMBI_MAX_CHANNELS] = { [0] = MMBI_APP_INTF_MCTP_NETDEV }; ++static int app_interface_count; ++module_param_array(app_interface, uint, &app_interface_count, 0444); ++MODULE_PARM_DESC(app_interface, ++ "App interface per channel: 0=ioctl, 1=mctp-netdev; one value applies to all channels"); ++ ++#endif ++ +struct aspeed_pci_bmc_dev { + struct device *dev; + struct miscdevice miscdev; @@ -57148,12 +57307,9 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + * The index of array is using to enum msi_index + */ + int *msi_idx_table; -+ -+ bool ast2700_soc1; -+ -+ /* AST2700 MMBI */ -+ struct aspeed_pcie_mmbi mmbi[MMBI_MAX_INST]; -+ int mmbi_start_msi; ++#if IS_ENABLED(CONFIG_ASPEED_MMBI) ++ struct aspeed_host_pcie_mmbi mmbi; ++#endif +}; + +#define PCIE_DEVICE_SIO_ADDR (0x2E * 4) @@ -57161,465 +57317,6 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + +#define DRIVER_NAME "aspeed-host-bmc-dev" + -+static int mmbi_desc_init(struct aspeed_mmbi_channel *chan); -+ -+static u8 mmbi_get_bmc_rdy(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ -+ return hros.b_rdy; -+} -+ -+static u8 mmbi_get_bmc_up(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ -+ return hros.b_up; -+} -+ -+static u8 mmbi_get_bmc_rst(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ -+ return hros.b_rst; -+} -+ -+static u8 mmbi_get_host_rst(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ -+ return hrws.h_rst; -+} -+ -+static u8 mmbi_get_host_up(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ -+ return hrws.h_up; -+} -+ -+static void mmbi_set_host_rst(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ hrws.h_rst = set; -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+} -+ -+static void mmbi_set_host_rdy(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ hrws.h_rdy = set; -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+} -+ -+static void mmbi_set_host_up(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ hrws.h_up = set; -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+} -+ -+static void get_h2b_avail_buf_len(struct aspeed_mmbi_channel *chan, ssize_t *avail_buf_len) -+{ -+ struct device *dev = chan->dev; -+ u32 h2b_rp, h2b_wp; -+ -+ h2b_rp = GET_H2B_READ_POINTER(chan); -+ h2b_wp = GET_H2B_WRITE_POINTER(chan); -+ dev_dbg(dev, "MMBI HRWS - h2b_rp: 0x%0x, h2b_wp: 0x%0x\n", h2b_rp, h2b_wp); -+ -+ if (h2b_wp >= h2b_rp) -+ *avail_buf_len = chan->h2b_cb_size - h2b_wp + h2b_rp; -+ else -+ *avail_buf_len = h2b_rp - h2b_wp; -+} -+ -+static u8 mmbi_get_state(struct aspeed_mmbi_channel *chan) -+{ -+ u8 state = 0; -+ -+ state = mmbi_get_bmc_up(chan) << 3; -+ state |= mmbi_get_bmc_rst(chan) << 2; -+ state |= mmbi_get_host_up(chan) << 1; -+ state |= mmbi_get_host_rst(chan); -+ -+ dev_dbg(chan->dev, "MMBI state: 0x%x\n", state); -+ -+ return state; -+} -+ -+static void raise_h2b_interrupt(struct aspeed_mmbi_channel *chan) -+{ -+ if (!chan->bmc_int_en) -+ return; -+ -+ writeb(chan->bmc_int_value, chan->desc_vmem + chan->bmc_int_location); -+} -+ -+static int mmbi_state_check(struct aspeed_mmbi_channel *chan) -+{ -+ enum mmbi_state current_state = mmbi_get_state(chan); -+ struct device *dev = chan->dev; -+ int ret; -+ -+ switch (current_state) { -+ case INIT_COMPLETED: -+ dev_dbg(dev, "Get INIT_COMPLETED state from BMC"); -+ -+ ret = mmbi_desc_init(chan); -+ if (ret) { -+ dev_warn(dev, "Check MMBI signature timeout\n"); -+ raise_h2b_interrupt(chan); -+ } -+ return 1; -+ case RESET_REQ_BY_BMC: -+ dev_dbg(dev, "Get RESET_REQ_BY_BMC state from BMC"); -+ -+ /* Change state to RESET_ACKED */ -+ mmbi_set_host_rst(chan, 1); -+ -+ dev_dbg(dev, "Change state to RESET_ACKED to BMC"); -+ raise_h2b_interrupt(chan); -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int mmbi_bmc_up_check(struct aspeed_mmbi_channel *chan) -+{ -+ u64 __timeout_us = 1000; -+ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); -+ -+ for (;;) { -+ enum mmbi_state current_state = mmbi_get_state(chan); -+ -+ if (current_state == INIT_COMPLETED) -+ break; -+ if (__timeout_us && ktime_compare(ktime_get(), __timeout) > 0) -+ return -EAGAIN; -+ } -+ -+ return 0; -+} -+ -+static void update_host_rws(struct aspeed_mmbi_channel *chan, unsigned int w_len, -+ unsigned int r_len) -+{ -+ struct device *dev = chan->dev; -+ struct host_rws hrws; -+ u32 h2b_wp, b2h_rp; -+ -+ h2b_wp = GET_H2B_WRITE_POINTER(chan); -+ b2h_rp = GET_B2H_READ_POINTER(chan); -+ -+ dev_dbg(dev, "MMBI HRWS - b2h_rp: 0x%0x, h2b_wp: 0x%0x\n", b2h_rp, h2b_wp); -+ -+ /* Advance the H2B CB offset for next write */ -+ if ((h2b_wp + w_len) <= chan->h2b_cb_size) -+ h2b_wp += w_len; -+ else -+ h2b_wp = h2b_wp + w_len - chan->h2b_cb_size; -+ -+ /* Advance the B2H CB offset till where BMC read data */ -+ if ((b2h_rp + r_len) <= chan->b2h_cb_size) -+ b2h_rp += r_len; -+ else -+ b2h_rp = b2h_rp + r_len - chan->b2h_cb_size; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ -+ hrws.h2b_wp = FIELD_GET(H2B_WRITE_POINTER_MASK, h2b_wp); -+ hrws.b2h_rp = FIELD_GET(B2H_READ_POINTER_MASK, b2h_rp); -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+ dev_dbg(dev, "Updating HRWS - b2h_rp: 0x%0x, h2b_wp: 0x%0x\n", b2h_rp, h2b_wp); -+ -+ if (w_len != 0) -+ raise_h2b_interrupt(chan); -+} -+ -+static int get_mmbi_header(struct aspeed_mmbi_channel *chan, u32 *data_length, u8 *type, -+ u32 *unread_data_len, u8 *padding) -+{ -+ u32 h2b_wp, h2b_rp, b2h_wp, b2h_rp; -+ struct mmbi_header header; -+ -+ h2b_wp = GET_H2B_WRITE_POINTER(chan); -+ h2b_rp = GET_H2B_READ_POINTER(chan); -+ b2h_wp = GET_B2H_WRITE_POINTER(chan); -+ b2h_rp = GET_B2H_READ_POINTER(chan); -+ dev_dbg(chan->dev, "MMBI HRWS - h2b_wp: 0x%0x, b2h_rp: 0x%0x\n", h2b_wp, b2h_rp); -+ dev_dbg(chan->dev, "MMBI HROS - b2h_wp: 0x%0x, h2b_rp: 0x%0x\n", b2h_wp, h2b_rp); -+ -+ if (b2h_wp >= b2h_rp) -+ *unread_data_len = b2h_wp - b2h_rp; -+ else -+ *unread_data_len = chan->b2h_cb_size - b2h_rp + b2h_wp; -+ -+ if (*unread_data_len < sizeof(struct mmbi_header)) { -+ dev_dbg(chan->dev, "No data to read(%d - %d)\n", b2h_wp, b2h_rp); -+ return -EAGAIN; -+ } -+ -+ dev_dbg(chan->dev, "READ MMBI header from: %p\n", chan->b2h_cb_vmem + b2h_rp); -+ -+ /* Extract MMBI protocol - protocol type and length */ -+ if ((b2h_rp + sizeof(header)) <= chan->b2h_cb_size) { -+ memcpy_fromio(&header, chan->b2h_cb_vmem + b2h_rp, sizeof(header)); -+ } else { -+ ssize_t chunk_len = chan->b2h_cb_size - b2h_rp; -+ -+ memcpy_fromio(&header, chan->b2h_cb_vmem + b2h_rp, chunk_len); -+ memcpy_fromio(((u8 *)&header) + chunk_len, chan->b2h_cb_vmem, -+ sizeof(header) - chunk_len); -+ } -+ -+ *data_length = (header.pkt_len << 2) - sizeof(header) - header.pkt_pad; -+ *padding = header.pkt_pad; -+ *type = header.pkt_type; -+ -+ return 0; -+} -+ -+static int aspeed_mmbi_write(struct aspeed_mmbi_channel *chan, const char *buffer, size_t len, -+ protocol_type type) -+{ -+ struct device *dev = chan->dev; -+ struct mmbi_header header = {0}; -+ ssize_t avail_buf_len; -+ ssize_t total_len; -+ ssize_t wt_offset; -+ ssize_t chunk_len; -+ ssize_t end_offset; -+ u8 padding = 0; -+ -+ /* If BMC READY bit is not set, Just discard the write. */ -+ if (!GET_BMC_READY_BIT(chan)) { -+ dev_dbg(dev, "Host not ready, discarding request...\n"); -+ return -EAGAIN; -+ } -+ -+ get_h2b_avail_buf_len(chan, &avail_buf_len); -+ -+ dev_dbg(dev, "H2B buffer empty space: %zd\n", avail_buf_len); -+ -+ /* Header size */ -+ total_len = len + 4; -+ -+ padding = total_len & 0x3; -+ if (padding) -+ padding = 4 - padding; -+ total_len += padding; -+ -+ /* Empty space should be more than write request data size */ -+ if (avail_buf_len <= sizeof(header) || (total_len > (avail_buf_len - sizeof(header)))) -+ return -ENOSPC; -+ -+ /* Fill multi-protocol header */ -+ header.pkt_type = type; -+ header.pkt_len = total_len >> 2; -+ header.pkt_pad = padding; -+ -+ wt_offset = GET_H2B_WRITE_POINTER(chan); -+ end_offset = chan->h2b_cb_size; -+ -+ /* Copy Header */ -+ if ((end_offset - wt_offset) >= sizeof(header)) { -+ memcpy_toio(chan->h2b_cb_vmem + wt_offset, &header, sizeof(header)); -+ wt_offset += sizeof(header); -+ } else { -+ chunk_len = end_offset - wt_offset; -+ dev_dbg(dev, "Write header chunk_len: %zd\n", chunk_len); -+ memcpy_toio(chan->h2b_cb_vmem + wt_offset, &header, chunk_len); -+ memcpy_toio(chan->h2b_cb_vmem, (u8 *)&header + chunk_len, -+ (sizeof(header) - chunk_len)); -+ wt_offset = (sizeof(header) - chunk_len); -+ } -+ -+ /* Write the data */ -+ if ((end_offset - wt_offset) >= len) { -+ memcpy_toio(&chan->h2b_cb_vmem[wt_offset], buffer, len); -+ wt_offset += len; -+ } else { -+ chunk_len = end_offset - wt_offset; -+ dev_dbg(dev, "Write data chunk_len: %zd\n", chunk_len); -+ memcpy_toio(&chan->h2b_cb_vmem[wt_offset], buffer, chunk_len); -+ wt_offset = 0; -+ memcpy_toio(&chan->h2b_cb_vmem[wt_offset], buffer + chunk_len, len - chunk_len); -+ wt_offset += len - chunk_len; -+ } -+ -+ update_host_rws(chan, total_len, 0); -+ -+ return 0; -+} -+ -+static void aspeed_mmbi_read(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, u8 padding) -+{ -+ struct device *dev = chan->dev; -+ ssize_t rd_offset; -+ u32 b2h_rp; -+ -+ b2h_rp = GET_B2H_READ_POINTER(chan); -+ if ((b2h_rp + sizeof(struct mmbi_header)) <= chan->b2h_cb_size) -+ rd_offset = b2h_rp + sizeof(struct mmbi_header); -+ else -+ rd_offset = b2h_rp + sizeof(struct mmbi_header) - chan->b2h_cb_size; -+ -+ /* Extract data and copy to user space application */ -+ dev_dbg(dev, "READ MMBI Data from: %p and length: %zd\n", -+ chan->b2h_cb_vmem + rd_offset, len); -+ -+ if ((chan->b2h_cb_size - rd_offset) >= len) { -+ memcpy_fromio(buffer, chan->b2h_cb_vmem + rd_offset, len); -+ rd_offset += len; -+ } else { -+ ssize_t chunk_len; -+ -+ chunk_len = chan->b2h_cb_size - rd_offset; -+ dev_dbg(dev, "Read data chunk_len: %zd\n", chunk_len); -+ memcpy_fromio(buffer, chan->b2h_cb_vmem + rd_offset, chunk_len); -+ -+ rd_offset = 0; -+ memcpy_fromio(buffer + chunk_len, chan->b2h_cb_vmem + rd_offset, -+ len - chunk_len); -+ } -+ -+ update_host_rws(chan, 0, len + sizeof(struct mmbi_header) + padding); -+} -+ -+static void mctp_mmbi_rx(struct aspeed_mmbi_channel *chan) -+{ -+ struct net_device *ndev; -+ struct sk_buff *skb; -+ struct mctp_skb_cb *cb; -+ u32 req_data_len, unread_data_len; -+ u8 type, padding; -+ int status; -+ -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; -+ -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d, Unread data: %d\n", __func__, -+ req_data_len, type, unread_data_len); -+ -+ ndev = chan->ndev; -+ -+ skb = netdev_alloc_skb(ndev, req_data_len); -+ if (!skb) { -+ ndev->stats.rx_dropped++; -+ update_host_rws(chan, 0, req_data_len + sizeof(struct mmbi_header)); -+ return; -+ } -+ -+ skb->protocol = htons(ETH_P_MCTP); -+ aspeed_mmbi_read(chan, skb_put(skb, req_data_len), req_data_len, padding); -+ skb_reset_network_header(skb); -+ -+ cb = __mctp_cb(skb); -+ cb->halen = 0; -+ -+ status = netif_rx(skb); -+ if (status == NET_RX_SUCCESS) { -+ ndev->stats.rx_packets++; -+ ndev->stats.rx_bytes += req_data_len; -+ } else { -+ ndev->stats.rx_dropped++; -+ } -+} -+ -+static netdev_tx_t mctp_mmbi_tx(struct sk_buff *skb, struct net_device *ndev) -+{ -+ struct aspeed_mmbi_mctp *mctp = netdev_priv(ndev); -+ int ret; -+ -+ if (!mmbi_get_bmc_rdy(&mctp->mmbi->chan) || skb->len > MCTP_MMBI_MTU_MAX) { -+ ndev->stats.tx_dropped++; -+ goto out; -+ } -+ -+ ret = aspeed_mmbi_write(&mctp->mmbi->chan, skb->data, skb->len, MMBI_PROTOCOL_MCTP); -+ if (ret) { -+ netif_stop_queue(ndev); -+ return NETDEV_TX_BUSY; -+ } -+ -+ ndev->stats.tx_packets++; -+ ndev->stats.tx_bytes += skb->len; -+out: -+ kfree_skb(skb); -+ return NETDEV_TX_OK; -+} -+ -+static const struct net_device_ops mctp_mmbi_netdev_ops = { -+ .ndo_start_xmit = mctp_mmbi_tx, -+}; -+ -+static void aspeed_mctp_mmbi_setup(struct net_device *ndev) -+{ -+ ndev->type = ARPHRD_MCTP; -+ -+ /* we limit at the fixed MTU, which is also the MCTP-standard -+ * baseline MTU, so is also our minimum -+ */ -+ ndev->mtu = MCTP_MMBI_MTU; -+ ndev->max_mtu = MCTP_MMBI_MTU_MAX; -+ ndev->min_mtu = MCTP_MMBI_MTU_MIN; -+ -+ ndev->hard_header_len = 0; -+ ndev->addr_len = 0; -+ ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; -+ ndev->flags = IFF_NOARP; -+ ndev->netdev_ops = &mctp_mmbi_netdev_ops; -+ ndev->needs_free_netdev = true; -+} -+ -+static int aspeed_mmbi_mctp_init(struct aspeed_mmbi_channel *chan) -+{ -+ struct aspeed_mmbi_mctp *mctp; -+ struct net_device *ndev; -+ char name[32]; -+ int ret; -+ -+ snprintf(name, sizeof(name), "mctpmmbi%d", chan->mmbi->id); -+ ndev = alloc_netdev(sizeof(*mctp), name, NET_NAME_ENUM, aspeed_mctp_mmbi_setup); -+ if (!ndev) -+ return -ENOMEM; -+ mctp = netdev_priv(ndev); -+ mctp->ndev = ndev; -+ mctp->mmbi = chan->mmbi; -+ -+ chan->ndev = ndev; -+ -+ ret = register_netdev(ndev); -+ if (ret) -+ goto free_netdev; -+ -+ return 0; -+ -+free_netdev: -+ free_netdev(ndev); -+ -+ return ret; -+} -+ +static struct aspeed_pci_bmc_dev *file_aspeed_bmc_device(struct file *file) +{ + return container_of(file->private_data, struct aspeed_pci_bmc_dev, miscdev); @@ -57746,67 +57443,13 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + return IRQ_HANDLED; +} + -+static void aspeed_mmbi_work_func(struct work_struct *workq) -+{ -+ struct aspeed_mmbi_channel *chan = container_of(workq, struct aspeed_mmbi_channel, work); -+ u32 weight = 256, req_data_len, unread_data_len; -+ u8 type, padding; -+ int i; -+ -+ for (i = 0; i < weight; i++) { -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; -+ -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d\n", -+ __func__, req_data_len, type); -+ -+ if (type == MMBI_PROTOCOL_MCTP) -+ mctp_mmbi_rx(chan); -+ else -+ /* Discard data and advance the hrws */ -+ update_host_rws(chan, 0, req_data_len + sizeof(struct mmbi_header) + padding); -+ -+ raise_h2b_interrupt(chan); -+ } -+ -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ queue_work(system_unbound_wq, &chan->work); -+} -+ -+static irqreturn_t aspeed_pci_mmbi_isr(int irq, void *dev_id) -+{ -+ struct aspeed_pcie_mmbi *mmbi = dev_id; -+ struct aspeed_mmbi_channel *chan = &mmbi->chan; -+ ssize_t avail_buf_len; -+ -+ get_h2b_avail_buf_len(chan, &avail_buf_len); -+ if (avail_buf_len > MCTP_MMBI_MTU_MAX) { -+ if (netif_queue_stopped(chan->ndev)) { -+ dev_dbg(chan->dev, "Wake up mctp net device\n"); -+ netif_wake_queue(chan->ndev); -+ } -+ } -+ -+ if (mmbi_state_check(chan)) -+ return IRQ_HANDLED; -+ -+ queue_work(system_unbound_wq, &chan->work); -+ -+ return IRQ_HANDLED; -+} -+ +static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); + + /* Assign static msi index table by platform */ + if (pdev->revision == 0x27) { -+ if (pci_bmc_dev->driver_data == ASPEED) { -+ pci_bmc_dev->msi_idx_table = ast2700_soc0_msi_idx_table; -+ } else { -+ pci_bmc_dev->msi_idx_table = ast2700_soc1_msi_idx_table; -+ pci_bmc_dev->ast2700_soc1 = true; -+ } ++ pci_bmc_dev->msi_idx_table = ast2700_soc0_msi_idx_table; + } else { + pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table; + } @@ -57952,231 +57595,6 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + return 0; +} + -+static int mmbi_signature_check(struct aspeed_mmbi_channel *chan) -+{ -+ u8 signature[6]; -+ u64 __timeout_us = 1000; -+ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); -+ -+ for (;;) { -+ memcpy_fromio(signature, chan->desc_vmem, 6); -+ if (!memcmp(MMBI_SIGNATURE, signature, 6)) -+ break; -+ if (__timeout_us && ktime_compare(ktime_get(), __timeout) > 0) -+ return -ETIMEDOUT; -+ } -+ return 0; -+} -+ -+static int mmbi_desc_init(struct aspeed_mmbi_channel *chan) -+{ -+ struct aspeed_pcie_mmbi *mmbi = chan->mmbi; -+ struct device *dev = chan->dev; -+ struct mmbi_cap_desc desc; -+ u8 __iomem *desc_base = chan->desc_vmem; -+ int ret; -+ -+ /* First, check mmbi signature "#MMBI$" */ -+ ret = mmbi_signature_check(chan); -+ if (ret) { -+ dev_warn(dev, "Check MMBI signature timeout\n"); -+ return ret; -+ } -+ -+ memcpy_fromio(&desc, chan->desc_vmem, sizeof(desc)); -+ -+ /* HROS */ -+ if (((desc.bt_desc.h_ros_p << 3) + sizeof(struct host_ros)) >= mmbi->mem_size) { -+ dev_warn(dev, "HROS is out of range"); -+ return -EINVAL; -+ } -+ chan->hros_vmem = desc_base + (desc.bt_desc.h_ros_p << 3); -+ -+ /* HRWS */ -+ if (((desc.bt_desc.h_rws_p << 3) + sizeof(struct host_rws)) >= mmbi->mem_size) { -+ dev_warn(dev, "HRWS is out of range"); -+ return -EINVAL; -+ } -+ chan->hrws_vmem = desc_base + (desc.bt_desc.h_rws_p << 3); -+ -+ ret = mmbi_bmc_up_check(chan); -+ if (ret) { -+ dev_warn(dev, "Check BMC up timeout\n"); -+ return ret; -+ } -+ -+ /* Implementations of MMBI described in this document shall indicate version 1 of MMBI */ -+ if (desc.version != 1) { -+ dev_warn(dev, "MMBI version must be 1"); -+ goto err_mismatch; -+ } -+ -+ /* This MMBI interface is intended for OS use */ -+ if (desc.os_use != 1) { -+ dev_warn(dev, "This MMBI does not provide for OS"); -+ goto err_mismatch; -+ } -+ -+ /* Current application is only MMBI Variable Packet Size Circular Buffers (VPSCB) v1 */ -+ if (desc.buffer_type != 1) { -+ dev_warn(dev, "The buffer type is not VPSCB: (%d)", desc.buffer_type); -+ goto err_mismatch; -+ } -+ -+ /* B2H Buffer */ -+ if (((desc.b2h_ba << 3) + desc.b2h_l) > mmbi->mem_size) { -+ dev_warn(dev, "B2H buffer is out of range"); -+ goto err_mismatch; -+ } -+ chan->b2h_cb_vmem = desc_base + (desc.b2h_ba << 3); -+ chan->b2h_cb_size = desc.b2h_l; -+ -+ /* H2B Buffer */ -+ if (((desc.h2b_ba << 3) + desc.h2b_l) > mmbi->mem_size) { -+ dev_warn(dev, "H2B buffer is out of range"); -+ goto err_mismatch; -+ } -+ chan->h2b_cb_vmem = desc_base + (desc.h2b_ba << 3); -+ chan->h2b_cb_size = desc.h2b_l; -+ -+ dev_dbg(dev, "B2H mapped addr - desc: %p, hros: %p, b2h_cb: %p\n", -+ chan->desc_vmem, chan->hros_vmem, chan->b2h_cb_vmem); -+ dev_dbg(dev, "H2B mapped addr - hrws: %p, h2b_cb: %p\n", chan->hrws_vmem, -+ chan->h2b_cb_vmem); -+ -+ dev_dbg(dev, "B2H buffer size: 0x%0x\n", chan->b2h_cb_size); -+ dev_dbg(dev, "H2B buffer size: 0x%0x\n", chan->h2b_cb_size); -+ -+ /* Host Interrupt */ -+ chan->host_int_en = !!desc.bt_desc.h_int_t; -+ if (chan->host_int_en) { -+ /* 1 for PCIe */ -+ if (desc.bt_desc.h_int_t != 1) -+ chan->host_int_en = 0; -+ else -+ chan->host_int_location = desc.bt_desc.h_int_l; -+ } -+ -+ /* BMC Interrupt */ -+ chan->bmc_int_en = !!desc.bt_desc.bmc_int_t; -+ if (chan->bmc_int_en) { -+ if (desc.bt_desc.bmc_int_t != 1) { -+ chan->bmc_int_en = 0; -+ } else { -+ chan->bmc_int_location = desc.bt_desc.bmc_int_l; -+ chan->bmc_int_vmem = desc_base + chan->bmc_int_location; -+ chan->bmc_int_value = desc.bt_desc.bmc_int_v; -+ } -+ } -+ -+ INIT_WORK(&chan->work, aspeed_mmbi_work_func); -+ -+ return 0; -+err_mismatch: -+ /* Change state to INIT_MISMATCH */ -+ mmbi_set_host_rst(chan, 1); -+ return -EINVAL; -+} -+ -+static int aspeed_pci_mmbi_init(struct aspeed_pcie_mmbi *mmbi) -+{ -+ struct aspeed_mmbi_channel *chan = &mmbi->chan; -+ struct device *dev = chan->dev; -+ int ret; -+ -+ chan->desc_vmem = mmbi->mem; -+ chan->mmbi = mmbi; -+ -+ ret = mmbi_desc_init(chan); -+ if (ret) { -+ dev_err(dev, "Unable to init mmbi desc\n"); -+ return ret; -+ } -+ -+ /* Initialize MTCP function */ -+ ret = aspeed_mmbi_mctp_init(chan); -+ if (ret) { -+ dev_err(dev, "Unable to init mctp\n"); -+ return ret; -+ } -+ -+ /* Change state to NORMAL_RUNTIME */ -+ mmbi_set_host_up(chan, 1); -+ mmbi_set_host_rdy(chan, 1); -+ /* Trigger BMC to finish normal runtime state */ -+ raise_h2b_interrupt(chan); -+ -+ return 0; -+} -+ -+/* AST2700 PCIe MMBI -+ * SoC : | 0 | 1 | -+ * BAR : | 2 3 4 5 | 0 1 2 3 4 5 | -+ * MMBI: | 0 1 2 3 | 0 1 2 3 4 5 | -+ */ -+static void aspeed_pci_bmc_device_setup_mmbi(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ struct aspeed_pcie_mmbi *mmbi; -+ u32 start_bar = 2, mmbi_max_inst = 4, start_msi = MMBI0_MSI; /* AST2700 SoC0 */ -+ int i, rc = 0; -+ -+ /* AST2700 A1 supports MMBI */ -+ if (pdev->revision != 0x27) -+ return; -+ -+ if (pci_bmc_dev->ast2700_soc1) { -+ /* AST2700 SoC1 */ -+ start_bar = 0; -+ mmbi_max_inst = 6; -+ start_msi = 0; -+ } -+ -+ for (i = 0; i < mmbi_max_inst; i++) { -+ mmbi = &pci_bmc_dev->mmbi[i]; -+ -+ /* Get MMBI BAR resource */ -+ mmbi->base = pci_resource_start(pdev, start_bar + i); -+ mmbi->mem_size = pci_resource_len(pdev, start_bar + i); -+ -+ /* Check if there is bar */ -+ if (!mmbi->mem_size) -+ continue; -+ -+ mmbi->mem = pci_ioremap_bar(pdev, start_bar + i); -+ if (!mmbi->mem) { -+ mmbi->mem_size = 0; -+ continue; -+ } -+ -+ mmbi->chan.dev = &pdev->dev; -+ mmbi->dev_name = devm_kasprintf(mmbi->chan.dev, GFP_KERNEL, "pci-mmbi%d", i); -+ mmbi->id = i; -+ rc = aspeed_pci_mmbi_init(mmbi); -+ if (rc < 0) { -+ pr_err("Initialize MMBI device failed.\n"); -+ goto free_ioremap; -+ } -+ -+ if (mmbi->chan.host_int_en) { -+ mmbi->irq = pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[start_msi + i]); -+ rc = devm_request_irq(&pdev->dev, mmbi->irq, aspeed_pci_mmbi_isr, -+ IRQF_SHARED, mmbi->dev_name, mmbi); -+ if (rc) { -+ pr_err("MMBI device %s unable to get IRQ %d\n", mmbi->dev_name, rc); -+ mmbi->irq = 0; -+ goto free_ioremap; -+ } -+ } else { -+ mmbi->irq = 0; -+ } -+ continue; -+free_ioremap: -+ mmbi->mem_size = 0; -+ pci_iounmap(pdev, mmbi->mem); -+ } -+} -+ +static void aspeed_pci_host_bmc_device_release_queue(struct pci_dev *pdev) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); @@ -58205,35 +57623,6 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + misc_deregister(&pci_bmc_dev->miscdev); +} + -+static void aspeed_pci_release_mmbi(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ struct aspeed_pcie_mmbi *mmbi; -+ int i; -+ -+ if (pdev->revision != 0x27) -+ return; -+ -+ for (i = 0; i < MMBI_MAX_INST; i++) { -+ mmbi = &pci_bmc_dev->mmbi[i]; -+ -+ if (mmbi->mem_size == 0) -+ continue; -+ -+ cancel_work_sync(&mmbi->chan.work); -+ -+ mmbi_set_host_rdy(&mmbi->chan, 0); -+ mmbi_set_host_up(&mmbi->chan, 0); -+ -+ unregister_netdev(mmbi->chan.ndev); -+ -+ if (mmbi->mem) -+ pci_iounmap(pdev, mmbi->mem); -+ if (mmbi->irq != 0) -+ devm_free_irq(&pdev->dev, mmbi->irq, mmbi); -+ } -+} -+ +static int aspeed_pci_host_setup(struct pci_dev *pdev) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); @@ -58291,9 +57680,6 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + goto out_free_uart; + } + -+ /* Setup AST2700 PCIe MMBI device */ -+ aspeed_pci_bmc_device_setup_mmbi(pdev); -+ + return 0; + +out_free_uart: @@ -58314,18 +57700,150 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + return rc; +} + -+static int aspeed_pci_host_mmbi_device_setup(struct pci_dev *pdev) -+{ -+ aspeed_pci_bmc_device_setup_mmbi(pdev); -+ return 0; -+} -+ +static struct aspeed_platform aspeed_pcie_host[] = { + { .setup = aspeed_pci_host_setup }, -+ { .setup = aspeed_pci_host_mmbi_device_setup }, + { 0 } +}; + ++#if IS_ENABLED(CONFIG_ASPEED_MMBI) ++static const char * ++aspeed_host_pcie_mmbi_app_interface_name(enum mmbi_app_interface intf) ++{ ++ switch (intf) { ++ case MMBI_APP_INTF_MCTP_NETDEV: ++ return "mctp-netdev"; ++ case MMBI_APP_INTF_IOCTL: ++ default: ++ return "ioctl"; ++ } ++} ++ ++static int aspeed_host_pcie_mmbi_validate_app_interface(struct device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < app_interface_count; i++) { ++ if (app_interface[i] > MMBI_APP_INTF_MCTP_NETDEV) { ++ dev_warn(dev, ++ "invalid app_interface[%d]=%u, using defaults\n", ++ i, app_interface[i]); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static enum mmbi_app_interface ++aspeed_host_pcie_mmbi_get_app_interface(int channel, bool use_defaults) ++{ ++ if (use_defaults) ++ return app_interface_defaults[channel]; ++ ++ if (app_interface_count == 1) ++ return app_interface[0]; ++ ++ if (channel < app_interface_count) ++ return app_interface[channel]; ++ ++ return app_interface_defaults[channel]; ++} ++ ++static void ++aspeed_host_pcie_mmbi_init_app_interfaces(struct mmbi_ins_desc *mmbi_desc, ++ bool use_defaults) ++{ ++ int i; ++ ++ for (i = 0; i < MMBI_MAX_CHANNELS; i++) ++ mmbi_desc->chan_desc[i].app_interface = ++ aspeed_host_pcie_mmbi_get_app_interface(i, ++ use_defaults); ++} ++ ++static void aspeed_host_pcie_mmbi_log_app_interfaces(struct device *dev, ++ struct mmbi_ins_desc *mmbi_desc, ++ int bar) ++{ ++ struct mmbi_chan_desc *chan_desc; ++ const char *interface; ++ int i; ++ ++ for (i = 0; i < mmbi_desc->num_of_channels; i++) { ++ chan_desc = &mmbi_desc->chan_desc[i]; ++ interface = aspeed_host_pcie_mmbi_app_interface_name(chan_desc->app_interface); ++ dev_info(dev, "BAR %d channel %d application interface: %s\n", ++ bar, i, interface); ++ } ++} ++ ++static int aspeed_pci_host_mmbi_setup(struct pci_dev *pdev) ++{ ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ struct aspeed_host_pcie_mmbi *mmbi = &pci_bmc_dev->mmbi; ++ struct aspeed_host_pcie_mmbi_ins *ins; ++ struct device *dev = &pdev->dev; ++ struct mmbi_ins_desc *mmbi_desc; ++ int i, ret, instance_id; ++ int last_ret = -ENODEV; ++ bool use_default_app_interfaces; ++ resource_size_t start, size; ++ ++ ret = aspeed_host_pcie_mmbi_validate_app_interface(dev); ++ use_default_app_interfaces = ret != 0; ++ ++ instance_id = 0; ++ for (i = 2; i < PCI_STD_NUM_BARS; i++) { ++ ins = &mmbi->instances[i]; ++ mmbi_desc = &ins->mmbi_desc; ++ start = pci_resource_start(pdev, i); ++ size = pci_resource_len(pdev, i); ++ ++ if (!start || !size) { ++ dev_err(dev, ++ "Invalid BAR %d with start 0x%llx and size 0x%llx\n", ++ i, (unsigned long long)start, ++ (unsigned long long)size); ++ continue; ++ } ++ ++ mmbi_desc->desc_virt = pci_ioremap_bar(pdev, i); ++ if (!mmbi_desc->desc_virt) { ++ dev_err(dev, "Failed to ioremap BAR %d\n", i); ++ continue; ++ } ++ mmbi_desc->dev = dev; ++ mmbi_desc->role = MMBI_ROLE_HOST; ++ ++ aspeed_host_pcie_mmbi_init_app_interfaces(mmbi_desc, ++ use_default_app_interfaces); ++ ret = mmbi_instance_init(mmbi_desc); ++ if (ret) { ++ dev_info(dev, ++ "Failed to initialize MMBI at bar %d, error %d\n", ++ i, ret); ++ pci_iounmap(pdev, mmbi_desc->desc_virt); ++ last_ret = ret; ++ } else { ++ ins->instance_index = instance_id++; ++ ins->bar_index = i; ++ ins->valid = true; ++ ins->dev_name = devm_kasprintf(dev, GFP_KERNEL, ++ "mmbi_host_ins%d", ++ ins->instance_index); ++ aspeed_host_pcie_mmbi_log_app_interfaces(dev, mmbi_desc, i); ++ ++ ins->msi_index = mmbi_desc->host_int_location; ++ } ++ } ++ ++ if (!instance_id) ++ return last_ret; ++ ++ return 0; ++} ++#endif ++ +static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev; @@ -58366,25 +57884,44 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + return rc; + } + ++#if IS_ENABLED(CONFIG_ASPEED_MMBI) ++ pci_bmc_dev->mmbi.dev = &pdev->dev; ++ rc = aspeed_pci_host_mmbi_setup(pdev); ++ if (rc) { ++ dev_err(&pdev->dev, "Failed to setup MMBI instances\n"); ++ return rc; ++ } ++#endif ++ + return 0; +} + +static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++#if IS_ENABLED(CONFIG_ASPEED_MMBI) ++ struct aspeed_host_pcie_mmbi *mmbi = &pci_bmc_dev->mmbi; ++ struct aspeed_host_pcie_mmbi_ins *ins; ++ int i; + -+ if (pci_bmc_dev->driver_data == ASPEED) { -+ aspeed_pci_host_bmc_device_release_queue(pdev); -+ aspeed_pci_host_bmc_device_release_memory_mapping(pdev); -+ aspeed_pci_host_bmc_device_release_vuart(pdev); -+ -+ devm_free_irq(&pdev->dev, pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[BMC_MSI]), -+ pci_bmc_dev); -+ devm_free_irq(&pdev->dev, pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[MBX_MSI]), -+ pci_bmc_dev); ++ for (i = 2; i < PCI_STD_NUM_BARS; i++) { ++ ins = &mmbi->instances[i]; ++ if (ins->valid) { ++ mmbi_instance_remove(&ins->mmbi_desc); ++ pci_iounmap(pdev, ins->mmbi_desc.desc_virt); ++ } + } ++#endif ++ aspeed_pci_host_bmc_device_release_queue(pdev); ++ aspeed_pci_host_bmc_device_release_memory_mapping(pdev); ++ aspeed_pci_host_bmc_device_release_vuart(pdev); + -+ aspeed_pci_release_mmbi(pdev); ++ devm_free_irq(&pdev->dev, ++ pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[BMC_MSI]), ++ pci_bmc_dev); ++ devm_free_irq(&pdev->dev, ++ pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[MBX_MSI]), ++ pci_bmc_dev); + + ida_simple_remove(&bmc_device_ida, pci_bmc_dev->id); + @@ -58401,12 +57938,8 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee + * + */ +static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = { -+ /* ASPEED BMC Device */ -+ { PCI_DEVICE(0x1A03, 0x2402), .class = 0xFF0000, .class_mask = 0xFFFF00, -+ .driver_data = ASPEED }, -+ /* AST2700 SoC1 MMBI device */ -+ { PCI_DEVICE(0x1A03, 0x2402), .class = 0x0C0C00, .class_mask = (0xFFFF00), -+ .driver_data = ASPEED_AST2700_SOC1 }, ++ { PCI_DEVICE(0x1A03, 0x2402), .class = 0xFF0000, .class_mask = 0xFFFF00 }, ++ { PCI_DEVICE(0x1A03, 0x2402), .class = 0x0C0C00, .class_mask = 0xFFFF00 }, + { + 0, + } @@ -58438,21 +57971,9 @@ diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspee +MODULE_AUTHOR("Ryan Chen "); +MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c ---- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c 2025-12-23 10:16:21.124032669 +0000 -@@ -353,7 +353,7 @@ - .of_match_table = aspeed_lpc_ctrl_match, - }, - .probe = aspeed_lpc_ctrl_probe, -- .remove_new = aspeed_lpc_ctrl_remove, -+ .remove = aspeed_lpc_ctrl_remove, - }; - - module_platform_driver(aspeed_lpc_ctrl_driver); diff --git a/drivers/soc/aspeed/aspeed-lpc-mbox.c b/drivers/soc/aspeed/aspeed-lpc-mbox.c --- a/drivers/soc/aspeed/aspeed-lpc-mbox.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-lpc-mbox.c 2025-12-23 10:16:21.124032669 +0000 ++++ b/drivers/soc/aspeed/aspeed-lpc-mbox.c 2026-09-09 15:51:44.718238072 +0000 @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* @@ -58862,8 +58383,8 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-mbox.c b/drivers/soc/aspeed/aspeed-lp +MODULE_DESCRIPTION("Aspeed mailbox device driver"); diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc-pcc.c --- a/drivers/soc/aspeed/aspeed-lpc-pcc.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-lpc-pcc.c 2025-12-23 10:16:21.124032669 +0000 -@@ -0,0 +1,438 @@ ++++ b/drivers/soc/aspeed/aspeed-lpc-pcc.c 2026-09-09 15:51:44.718238072 +0000 +@@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. @@ -58939,6 +58460,9 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc + +#define PCC_DMA_BUFSZ (256 * SZ_1K) + ++/* Except for the 1-byte threshold, the rest represent fractions of the FIFO. ++ * Ex. PCC_FIFO_THR_1_EIGHTH means 1/8th of the FIFO size. ++ */ +enum pcc_fifo_threshold { + PCC_FIFO_THR_1_BYTE, + PCC_FIFO_THR_1_EIGHTH, @@ -58948,7 +58472,6 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc + PCC_FIFO_THR_5_EIGHTH, + PCC_FIFO_THR_6_EIGHTH, + PCC_FIFO_THR_7_EIGHTH, -+ PCC_FIFO_THR_8_EIGHTH, +}; + +enum pcc_record_mode { @@ -58982,6 +58505,7 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc + wait_queue_head_t wq; + struct miscdevice mdev; + int mdev_id; ++ spinlock_t lock; /* protects access to the FIFO and DMA pointer */ +}; + +static inline bool is_valid_rec_mode(uint32_t mode) @@ -59042,22 +58566,26 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc + struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; + struct kfifo *fifo = &pcc->fifo; + ++ spin_lock(&pcc->lock); + regmap_write_bits(pcc->regmap, PCCR2, PCCR2_INT_STATUS_DMA_DONE, PCCR2_INT_STATUS_DMA_DONE); + + regmap_read(pcc->regmap, PCCR6, ®); + wptr = (reg & PCCR6_DMA_CUR_ADDR) - (pcc->dma.addr & PCCR6_DMA_CUR_ADDR); + rptr = pcc->dma.rptr; + -+ do { -+ if (kfifo_is_full(fifo)) -+ kfifo_skip(fifo); -+ -+ kfifo_put(fifo, pcc->dma.virt[rptr]); -+ -+ rptr = (rptr + 1) % pcc->dma.size; -+ } while (rptr != wptr); ++ /* If kfifo is empty or has enough space, insert new data; ++ * otherwise, discard the new data. ++ */ ++ if (rptr <= wptr) { ++ kfifo_in(fifo, pcc->dma.virt + rptr, wptr - rptr); ++ } else { ++ /* Handle wrap-around case */ ++ kfifo_in(fifo, pcc->dma.virt + rptr, pcc->dma.size - rptr); ++ kfifo_in(fifo, pcc->dma.virt, wptr); ++ } + -+ pcc->dma.rptr = rptr; ++ pcc->dma.rptr = wptr; ++ spin_unlock(&pcc->lock); + + wake_up_interruptible(&pcc->wq); + @@ -59150,6 +58678,10 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc + PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE, + PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE); + ++ regmap_update_bits(pcc->regmap, PCCR0, ++ PCCR0_RX_TRIG_LVL_MASK, ++ PCC_FIFO_THR_2_EIGHTH << PCCR0_RX_TRIG_LVL_SHIFT); ++ + regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN, PCCR0_EN); + + return 0; @@ -59213,6 +58745,8 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc + if (rc) + return rc; + ++ spin_lock_init(&pcc->lock); ++ + /* Disable PCC to clean up DMA buffer before request IRQ. */ + rc = aspeed_pcc_disable(pcc); + if (rc) { @@ -59303,8 +58837,8 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for Aspeed Post Code Capture"); diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c ---- a/drivers/soc/aspeed/aspeed-lpc-snoop.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c 2025-12-23 10:16:21.124032669 +0000 +--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c 2026-09-09 15:51:44.718238072 +0000 @@ -11,7 +11,7 @@ */ @@ -59668,18 +59202,9 @@ diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-l static const struct aspeed_lpc_snoop_model_data ast2400_model_data = { .has_hicrb_ensnp = 0, }; -@@ -388,7 +375,7 @@ - .of_match_table = aspeed_lpc_snoop_match, - }, - .probe = aspeed_lpc_snoop_probe, -- .remove_new = aspeed_lpc_snoop_remove, -+ .remove = aspeed_lpc_snoop_remove, - }; - - module_platform_driver(aspeed_lpc_snoop_driver); diff --git a/drivers/soc/aspeed/aspeed-mbox.c b/drivers/soc/aspeed/aspeed-mbox.c --- a/drivers/soc/aspeed/aspeed-mbox.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-mbox.c 2025-12-23 10:16:21.124032669 +0000 ++++ b/drivers/soc/aspeed/aspeed-mbox.c 2026-09-09 15:51:44.718238072 +0000 @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* @@ -59978,7 +59503,7 @@ diff --git a/drivers/soc/aspeed/aspeed-mbox.c b/drivers/soc/aspeed/aspeed-mbox.c + { .compatible = "aspeed,aspeed-mbox" }, + {}, +}; -+MODULE_DEVICE_TABLE(of, mbox_test_match); ++MODULE_DEVICE_TABLE(of, mbox_cl_match); + +static struct platform_driver aspeed_mbox_driver = { + .driver = { @@ -59995,8 +59520,8 @@ diff --git a/drivers/soc/aspeed/aspeed-mbox.c b/drivers/soc/aspeed/aspeed-mbox.c +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c --- a/drivers/soc/aspeed/aspeed-mctp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-mctp.c 2025-12-23 10:16:21.124032669 +0000 -@@ -0,0 +1,2658 @@ ++++ b/drivers/soc/aspeed/aspeed-mctp.c 2026-09-09 15:51:44.718238072 +0000 +@@ -0,0 +1,2693 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020, Intel Corporation. + @@ -60029,6 +59554,9 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c +#include + +#include ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) ++#include ++#endif + +/* AST2600 MCTP Controller registers */ +#define ASPEED_MCTP_CTRL 0x000 @@ -60314,6 +59842,8 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + int packet_counter; + } rx_runaway_wa; + bool rx_warmup; ++ /* Device ID for the device instance */ ++ u8 dev_id; + u8 eid; + struct platform_device *peci_mctp; + /* Use the flag to identify RC or EP */ @@ -60329,8 +59859,9 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + /* Delayed work for periodic detection of Rx packets */ + struct delayed_work rx_det_dwork; + u32 rx_det_period_us; -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) + struct net_device *ndev; ++ bool pcie_vdm_enabled; +#endif +}; + @@ -60434,6 +59965,9 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + bdf = PCI_DEVID(GET_PCI_BUS_NUM(reg), devfn); + } + ++ if (!priv->rc_f && bdf == 0) ++ return -ENODEV; ++ + return bdf; +} + @@ -60764,7 +60298,7 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + } else { + wake_up_all(&client->wait_queue); + } -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) + mctp_pcie_vdm_receive_packet(priv->ndev); +#endif + aspeed_mctp_client_put(client); @@ -61936,7 +61470,7 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + return ret; +} + -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) +static int aspeed_mctp_pcie_vdm_op_send_pkt(struct device *dev, + u8 *data, size_t size) +{ @@ -61980,7 +61514,7 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + + if (IS_ERR(rx_packet)) { + if (PTR_ERR(rx_packet) == -ETIME) { -+ dev_dbg(priv->dev, "no packet received\n"); ++ dev_dbg(priv->dev, "all packet received\n"); + } else { + dev_err(priv->dev, "failed to receive packet: %ld\n", + PTR_ERR(rx_packet)); @@ -62010,6 +61544,23 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + .uninit = aspeed_mctp_pcie_vdm_op_uninit, +}; + ++static void aspeed_mctp_pcie_vdm_register(struct aspeed_mctp *priv) ++{ ++ struct net_device *ndev; ++ struct mctp_client *client; ++ char ifname[IFNAMSIZ]; ++ ++ /** use priv's default client to send/receive mctp packets */ ++ client = aspeed_mctp_create_client(priv); ++ aspeed_mctp_register_default_handler(client); ++ ++ snprintf(ifname, IFNAMSIZ, "mctppci%d", priv->dev_id); ++ ndev = mctp_pcie_vdm_add_dev(priv->dev, &aspeed_mctp_pcie_vdm_ops, ifname); ++ if (IS_ERR(ndev)) ++ dev_err(priv->dev, "Failed to add mctp pcie vdm device Err %ld\n", PTR_ERR(ndev)); ++ priv->ndev = ndev; ++} ++ +#endif + +static const struct file_operations aspeed_mctp_fops = { @@ -62107,9 +61658,15 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + } + aspeed_mctp_rx_trigger(&priv->rx); + aspeed_mctp_send_pcie_uevent(kobj, true); ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) ++ mctp_pcie_vdm_set_carrier(priv->ndev, true); ++#endif + } else { + schedule_delayed_work(&priv->pcie.rst_dwork, + msecs_to_jiffies(1000)); ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) ++ mctp_pcie_vdm_set_carrier(priv->ndev, false); ++#endif + } +} + @@ -62255,11 +61812,15 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + return PTR_ERR(priv->reset); + } + -+ if (priv->rc_f) { -+ priv->reset_dma = devm_reset_control_get_shared_by_index(priv->dev, 1); -+ if (IS_ERR(priv->reset_dma)) { -+ dev_err(priv->dev, "Failed to get ep reset!\n"); -+ return PTR_ERR(priv->reset_dma); ++ if (priv->match_data->dma_need_64bits_width) { ++ priv->reset_dma = NULL; ++ } else { ++ if (priv->rc_f) { ++ priv->reset_dma = devm_reset_control_get_shared_by_index(priv->dev, 1); ++ if (IS_ERR(priv->reset_dma)) { ++ dev_err(priv->dev, "Failed to get ep reset!\n"); ++ return PTR_ERR(priv->reset_dma); ++ } + } + } + priv->pcie.map = @@ -62290,6 +61851,12 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + BUILD_BUG_ON(TX_PACKET_COUNT >= TX_MAX_PACKET_COUNT); + BUILD_BUG_ON(RX_PACKET_COUNT >= RX_MAX_PACKET_COUNT); + ++ ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); ++ if (ret) { ++ dev_err(priv->dev, "cannot set 64-bits DMA mask\n"); ++ return ret; ++ } ++ + ret = of_reserved_mem_device_init(priv->dev); + if (ret) { + dev_err(priv->dev, "device does not have specific DMA pool: %d\n", @@ -62302,12 +61869,6 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + if (ret) + return ret; + -+ ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); -+ if (ret) { -+ dev_err(priv->dev, "cannot set 64-bits DMA mask\n"); -+ return ret; -+ } -+ + alloc_size = PAGE_ALIGN(priv->rx_packet_count * priv->match_data->packet_unit_size); + rx->data.vaddr = + dma_alloc_coherent(priv->dev, alloc_size, &rx->data.dma_handle, GFP_KERNEL); @@ -62399,8 +61960,8 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + aspeed_mctp_irq_enable(priv); + } + irq = platform_get_irq_byname(pdev, "pcie"); -+ if (!irq) -+ return -ENODEV; ++ if (irq < 0) ++ return irq; + + ret = devm_request_irq(priv->dev, irq, aspeed_mctp_pcie_rst_irq_handler, + IRQF_SHARED, dev_name(&pdev->dev), priv); @@ -62420,7 +61981,7 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + return ret; + } + -+ if (priv->rc_f) { ++ if (priv->rc_f && priv->reset_dma) { + ret = reset_control_deassert(priv->reset_dma); + if (ret) { + dev_warn(priv->dev, "Failed to deassert ep reset\n"); @@ -62486,22 +62047,6 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + goto out_drv; + } + -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+ struct net_device *ndev; -+ struct mctp_client *client; -+ -+ /** use priv's default client to send/receive mctp packets */ -+ client = aspeed_mctp_create_client(priv); -+ aspeed_mctp_register_default_handler(client); -+ -+ ndev = mctp_pcie_vdm_add_dev(priv->dev, &aspeed_mctp_pcie_vdm_ops); -+ if (IS_ERR(ndev)) { -+ dev_err(priv->dev, "Failed to add mctp pcie vdm device Err %ld\n", PTR_ERR(ndev)); -+ goto out_drv; -+ } -+ priv->ndev = ndev; -+#endif -+ + ret = aspeed_mctp_dma_init(priv); + if (ret) { + dev_err(priv->dev, "Failed to init DMA\n"); @@ -62510,4230 +62055,4805 @@ diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c + + ret = aspeed_mctp_hw_reset(priv); + if (ret) -+ goto out_drv; ++ goto out_dma; + + aspeed_mctp_channels_init(priv); + -+ id = of_alias_get_id(priv->dev->of_node, "mctp"); -+ if (id < 0) -+ return id; -+ priv->mctp_miscdev.parent = priv->dev; -+ priv->mctp_miscdev.minor = MISC_DYNAMIC_MINOR; -+ priv->mctp_miscdev.name = devm_kasprintf(priv->dev, GFP_KERNEL, "aspeed-mctp%d", id); -+ priv->mctp_miscdev.fops = &aspeed_mctp_fops; -+ ret = misc_register(&priv->mctp_miscdev); -+ if (ret) { -+ dev_err(priv->dev, "Failed to register miscdev\n"); -+ goto out_dma; -+ } -+ priv->mctp_miscdev.this_device->type = &aspeed_mctp_type; ++ id = of_alias_get_id(priv->dev->of_node, "mctp"); ++ if (id < 0) { ++ ret = id; ++ goto out_dma; ++ } ++ ++ priv->dev_id = id; ++ priv->mctp_miscdev.parent = priv->dev; ++ priv->mctp_miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->mctp_miscdev.name = devm_kasprintf(priv->dev, GFP_KERNEL, "aspeed-mctp%d", id); ++ priv->mctp_miscdev.fops = &aspeed_mctp_fops; ++ ret = misc_register(&priv->mctp_miscdev); ++ if (ret) { ++ dev_err(priv->dev, "Failed to register miscdev\n"); ++ goto out_dma; ++ } ++ priv->mctp_miscdev.this_device->type = &aspeed_mctp_type; ++ ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) ++ if (!priv->pcie_vdm_enabled) { ++ aspeed_mctp_pcie_vdm_register(priv); ++ priv->pcie_vdm_enabled = true; ++ } ++#endif ++ ++ ret = aspeed_mctp_irq_init(priv); ++ if (ret) { ++ dev_err(priv->dev, "Failed to init IRQ!\n"); ++ goto out_irq; ++ } ++ aspeed_mctp_pcie_setup(priv); ++ ++ name = devm_kasprintf(priv->dev, GFP_KERNEL, "peci-mctp%d", id); ++ priv->peci_mctp = ++ platform_device_register_data(priv->dev, name, PLATFORM_DEVID_NONE, NULL, 0); ++ if (IS_ERR(priv->peci_mctp)) ++ dev_err(priv->dev, "Failed to register peci-mctp device\n"); ++ ++ return 0; ++out_irq: ++ misc_deregister(&priv->mctp_miscdev); ++out_dma: ++ aspeed_mctp_dma_fini(priv); ++out_drv: ++ aspeed_mctp_drv_fini(priv); ++out: ++ dev_err(&pdev->dev, "Failed to probe Aspeed MCTP: %d\n", ret); ++ return ret; ++} ++ ++static void aspeed_mctp_remove(struct platform_device *pdev) ++{ ++ struct aspeed_mctp *priv = platform_get_drvdata(pdev); ++ ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) ++ if (priv->pcie_vdm_enabled) { ++ mctp_pcie_vdm_remove_dev(priv->ndev); ++ priv->pcie_vdm_enabled = false; ++ } ++#endif ++ ++ platform_device_unregister(priv->peci_mctp); ++ ++ misc_deregister(&priv->mctp_miscdev); ++ ++ aspeed_mctp_irq_disable(priv); ++ ++ aspeed_mctp_dma_fini(priv); ++ ++ aspeed_mctp_drv_fini(priv); ++} ++ ++static const struct aspeed_mctp_match_data ast2500_mctp_match_data = { ++ .rx_cmd_size = sizeof(struct aspeed_mctp_rx_cmd), ++ .tx_cmd_size = sizeof(struct aspeed_mctp_tx_cmd), ++ .packet_unit_size = 128, ++ .need_address_mapping = true, ++ .vdm_hdr_direct_xfer = false, ++ .fifo_auto_surround = false, ++}; ++ ++static const struct aspeed_mctp_match_data ast2600_mctp_match_data = { ++ .rx_cmd_size = sizeof(u32), ++ .tx_cmd_size = sizeof(struct aspeed_mctp_tx_cmd), ++ .packet_unit_size = sizeof(struct mctp_pcie_packet_data), ++ .need_address_mapping = false, ++ .vdm_hdr_direct_xfer = true, ++ .fifo_auto_surround = true, ++}; ++ ++static const struct aspeed_mctp_match_data ast2700_mctp0_match_data = { ++ .rx_cmd_size = sizeof(struct aspeed_mctp_rx_cmd), ++ .tx_cmd_size = sizeof(struct aspeed_g7_mctp_tx_cmd), ++ .packet_unit_size = sizeof(struct mctp_pcie_packet_data), ++ .need_address_mapping = false, ++ .vdm_hdr_direct_xfer = true, ++ .fifo_auto_surround = true, ++ .dma_need_64bits_width = true, ++ .scu_pcie_ctrl_offset = ASPEED_G7_SCU_PCIE0_CTRL_OFFSET, ++}; ++ ++static const struct aspeed_mctp_match_data ast2700_mctp1_match_data = { ++ .rx_cmd_size = sizeof(struct aspeed_mctp_rx_cmd), ++ .tx_cmd_size = sizeof(struct aspeed_g7_mctp_tx_cmd), ++ .packet_unit_size = sizeof(struct mctp_pcie_packet_data), ++ .need_address_mapping = false, ++ .vdm_hdr_direct_xfer = true, ++ .fifo_auto_surround = true, ++ .dma_need_64bits_width = true, ++ .scu_pcie_ctrl_offset = ASPEED_G7_SCU_PCIE1_CTRL_OFFSET, ++}; ++ ++static const struct of_device_id aspeed_mctp_match_table[] = { ++ { .compatible = "aspeed,ast2500-mctp", .data = &ast2500_mctp_match_data}, ++ { .compatible = "aspeed,ast2600-mctp", .data = &ast2600_mctp_match_data}, ++ { .compatible = "aspeed,ast2700-mctp0", .data = &ast2700_mctp0_match_data}, ++ { .compatible = "aspeed,ast2700-mctp1", .data = &ast2700_mctp1_match_data}, ++ { } ++}; ++ ++static struct platform_driver aspeed_mctp_driver = { ++ .driver = { ++ .name = "aspeed-mctp", ++ .of_match_table = of_match_ptr(aspeed_mctp_match_table), ++ }, ++ .probe = aspeed_mctp_probe, ++ .remove = aspeed_mctp_remove, ++}; ++ ++static int __init aspeed_mctp_init(void) ++{ ++ packet_cache = ++ kmem_cache_create_usercopy("mctp-packet", ++ sizeof(struct mctp_pcie_packet), ++ 0, 0, 0, ++ sizeof(struct mctp_pcie_packet), ++ NULL); ++ if (!packet_cache) ++ return -ENOMEM; ++ ++ return platform_driver_register(&aspeed_mctp_driver); ++} ++ ++static void __exit aspeed_mctp_exit(void) ++{ ++ platform_driver_unregister(&aspeed_mctp_driver); ++ kmem_cache_destroy(packet_cache); ++} ++ ++module_init(aspeed_mctp_init) ++module_exit(aspeed_mctp_exit) ++ ++MODULE_DEVICE_TABLE(of, aspeed_mctp_match_table); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Iwona Winiarska "); ++MODULE_DESCRIPTION("Aspeed MCTP driver"); +diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c +--- a/drivers/soc/aspeed/aspeed-socinfo.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-socinfo.c 2026-09-09 15:51:44.718238072 +0000 +@@ -39,7 +39,7 @@ + unsigned int i; + + for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) { +- if ((rev_table[i].id & 0xff00ffff) == id) ++ if (rev_table[i].id == id) + return rev_table[i].name; + } + +diff --git a/drivers/soc/aspeed/aspeed-ssp.c b/drivers/soc/aspeed/aspeed-ssp.c +--- a/drivers/soc/aspeed/aspeed-ssp.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-ssp.c 2026-09-09 15:51:44.718238072 +0000 +@@ -0,0 +1,277 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright (C) ASPEED Technology Inc. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SSP_FILE_NAME "ast2600_ssp.bin" ++#define AST2600_CVIC_TRIGGER 0x28 ++#define AST2600_CVIC_PENDING_STATUS 0x18 ++#define AST2600_CVIC_PENDING_CLEAR 0x1C ++ ++#define SSP_CTRL_REG 0xa00 ++#define SSP_CTRL_RESET_ASSERT BIT(1) ++#define SSP_CTRL_EN BIT(0) ++ ++#define SSP_MEM_BASE_REG 0xa04 ++#define SSP_IMEM_LIMIT_REG 0xa08 ++#define SSP_DMEM_LIMIT_REG 0xa0c ++#define SSP_CACHE_RANGE_REG 0xa40 ++#define SSP_CACHE_INVALID_REG 0xa44 ++#define SSP_CACHE_CTRL_REG 0xa48 ++#define SSP_CACHE_CLEAR_ICACHE BIT(2) ++#define SSP_CACHE_CLEAR_DCACHE BIT(1) ++#define SSP_CACHE_EN BIT(0) ++ ++#define SSP_TOTAL_MEM_SZ (32 * 1024 * 1024) ++#define SSP_CACHED_MEM_SZ (16 * 1024 * 1024) ++#define SSP_UNCACHED_MEM_SZ (SSP_TOTAL_MEM_SZ - SSP_CACHED_MEM_SZ) ++#define SSP_CACHE_1ST_16MB_ENABLE BIT(0) ++ ++struct ast2600_ssp { ++ struct device *dev; ++ struct regmap *scu; ++ dma_addr_t ssp_mem_phy_addr; ++ void __iomem *ssp_mem_vir_addr; ++ dma_addr_t ssp_shared_mem_phy_addr; ++ void __iomem *ssp_shared_mem_vir_addr; ++ int ssp_shared_mem_size; ++ void __iomem *cvic; ++ int irq[16]; ++ int n_irq; ++}; ++ ++static int ast_ssp_open(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static int ast_ssp_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static const struct file_operations ast_ssp_fops = { ++ .owner = THIS_MODULE, ++ .open = ast_ssp_open, ++ .release = ast_ssp_release, ++ .llseek = no_llseek, ++}; ++ ++struct miscdevice ast_ssp_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "ast-ssp", ++ .fops = &ast_ssp_fops, ++}; ++ ++static irqreturn_t ast2600_ssp_interrupt(int irq, void *dev_id) ++{ ++ u32 i; ++ struct ast2600_ssp *priv = dev_id; ++ u32 isr = readl(priv->cvic + AST2600_CVIC_PENDING_STATUS); ++ u32 ssp_shared_rx_tx_size = priv->ssp_shared_mem_size / 2; ++ u32 *ssp_shared_mem_tx = priv->ssp_shared_mem_vir_addr; ++ u32 *ssp_shared_mem_rx = priv->ssp_shared_mem_vir_addr + ssp_shared_rx_tx_size; ++ ++ dev_info(priv->dev, "isr %x\n", isr); ++ writel(isr, priv->cvic + AST2600_CVIC_PENDING_CLEAR); ++ ++ dev_info(priv->dev, "[CA7] rx addr:%08x, tx addr:%08x\n", ++ (u32)ssp_shared_mem_rx, (u32)ssp_shared_mem_tx); ++ ++ /* Check the CA7 RX data from CM3 TX data. */ ++ dev_info(priv->dev, "CA7 RX data from CM3 TX data: "); ++ for (i = 0; i < ssp_shared_rx_tx_size / 4; i++) { ++ if (readl(ssp_shared_mem_rx + i) != 0) { ++ dev_info(priv->dev, "[%08x] %08x ", ++ (u32)(ssp_shared_mem_rx + i), readl(ssp_shared_mem_rx + i)); ++ } else { ++ break; ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int ast_ssp_probe(struct platform_device *pdev) ++{ ++ struct device_node *np, *mnode = dev_of_node(&pdev->dev); ++ const struct firmware *firmware; ++ struct ast2600_ssp *priv; ++ struct reserved_mem *rmem; ++ int i, ret; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto finish; ++ } ++ ++ priv->dev = &pdev->dev; ++ priv->scu = syscon_regmap_lookup_by_phandle(priv->dev->of_node, "aspeed,scu"); ++ if (IS_ERR(priv->scu)) { ++ dev_err(priv->dev, "failed to find SCU regmap\n"); ++ ret = -EINVAL; ++ goto finish; ++ } ++ platform_set_drvdata(pdev, priv); ++ ++ ret = misc_register(&ast_ssp_misc); ++ if (ret) { ++ pr_err("can't misc_register :(\n"); ++ ret = -EIO; ++ goto finish; ++ } ++ dev_set_drvdata(ast_ssp_misc.this_device, pdev); ++ ++ ret = of_reserved_mem_device_init(&pdev->dev); ++ if (ret) { ++ dev_err(priv->dev, ++ "failed to initialize reserved mem: %d\n", ret); ++ ret = -ENOMEM; ++ goto finish; ++ } ++ ++ np = of_parse_phandle(priv->dev->of_node, "memory-region", 0); ++ if (!np) { ++ dev_err(priv->dev, "can't find memory-region node\n"); ++ ret = -ENOMEM; ++ goto finish; ++ } ++ ++ rmem = of_reserved_mem_lookup(np); ++ of_node_put(np); ++ if (!rmem) { ++ dev_err(priv->dev, "can't find reserved memory.\n"); ++ ret = -ENOMEM; ++ goto finish; ++ } else { ++ priv->ssp_mem_phy_addr = rmem->base; ++ priv->ssp_mem_vir_addr = devm_ioremap(priv->dev, priv->ssp_mem_phy_addr, SSP_TOTAL_MEM_SZ); ++ if (!priv->ssp_mem_vir_addr) { ++ dev_err(priv->dev, "can't create reserved memory.\n"); ++ ret = -ENOMEM; ++ goto finish; ++ } else { ++ dev_info(priv->dev, "\nSSP memory: virt(0x%08x), phys(0x%08x)\n", ++ (uint32_t)priv->ssp_mem_vir_addr, priv->ssp_mem_phy_addr); ++ } ++ } ++ ++ if (of_property_read_u32(np, "shm-size", &priv->ssp_shared_mem_size)) { ++ dev_err(priv->dev, "can't find shm-size property\n"); ++ ret = -ENOMEM; ++ goto finish; ++ } ++ ++ priv->ssp_shared_mem_vir_addr = priv->ssp_mem_vir_addr + SSP_TOTAL_MEM_SZ ++ - priv->ssp_shared_mem_size; ++ priv->ssp_shared_mem_phy_addr = priv->ssp_mem_phy_addr + SSP_TOTAL_MEM_SZ ++ - priv->ssp_shared_mem_size; ++ dev_info(priv->dev, "\nSSP shared memory: virt(0x%08x), phys(0x%08x), size(0x%08x)\n", ++ (uint32_t)priv->ssp_shared_mem_vir_addr, priv->ssp_shared_mem_phy_addr, ++ priv->ssp_shared_mem_size); ++ ++ if (request_firmware(&firmware, SSP_FILE_NAME, priv->dev) < 0) { ++ dev_err(priv->dev, "don't have %s\n", SSP_FILE_NAME); ++ release_firmware(firmware); ++ ret = -EINVAL; ++ goto finish; ++ } ++ ++ memcpy(priv->ssp_mem_vir_addr, (void *)firmware->data, firmware->size); ++ release_firmware(firmware); ++ ++ np = of_parse_phandle(mnode, "aspeed,cvic", 0); ++ if (!np) { ++ dev_err(priv->dev, "can't find CVIC\n"); ++ ret = -EINVAL; ++ goto finish; ++ } ++ ++ priv->cvic = devm_of_iomap(priv->dev, np, 0, NULL); ++ if (IS_ERR(priv->cvic)) { ++ dev_err(priv->dev, "can't map CVIC\n"); ++ ret = -EINVAL; ++ goto finish; ++ } ++ ++ i = 0; ++ while (0 != (priv->irq[i] = irq_of_parse_and_map(mnode, i))) { ++ ret = request_irq(priv->irq[i], ast2600_ssp_interrupt, 0, ++ "ssp-sw-irq", priv); ++ i++; ++ } ++ priv->n_irq = i; ++ dev_info(priv->dev, "%d ISRs registered\n", priv->n_irq); ++ ++ regmap_write(priv->scu, SSP_CTRL_REG, 0); ++ mdelay(1); ++ regmap_write(priv->scu, SSP_MEM_BASE_REG, priv->ssp_mem_phy_addr); ++ regmap_write(priv->scu, SSP_IMEM_LIMIT_REG, priv->ssp_mem_phy_addr + SSP_CACHED_MEM_SZ); ++ regmap_write(priv->scu, SSP_DMEM_LIMIT_REG, priv->ssp_mem_phy_addr + SSP_TOTAL_MEM_SZ); ++ ++ regmap_write(priv->scu, SSP_CACHE_RANGE_REG, SSP_CACHE_1ST_16MB_ENABLE); ++ ++ regmap_write(priv->scu, SSP_CTRL_REG, SSP_CTRL_RESET_ASSERT); ++ mdelay(1); ++ regmap_write(priv->scu, SSP_CTRL_REG, 0); ++ mdelay(1); ++ regmap_write(priv->scu, SSP_CTRL_REG, SSP_CTRL_EN); ++ ++ dev_info(priv->dev, "Init successful\n"); ++ ret = 0; ++finish: ++ return ret; ++} ++ ++static int ast_ssp_remove(struct platform_device *pdev) ++{ ++ struct ast2600_ssp *priv = platform_get_drvdata(pdev); ++ int i; ++ ++ dev_info(priv->dev, "SSP module removed\n"); ++ regmap_write(priv->scu, SSP_CTRL_REG, 0); ++ for (i = 0; i < priv->n_irq; i++) ++ free_irq(priv->irq[i], priv); ++ ++ kfree(priv); ++ ++ misc_deregister((struct miscdevice *)&ast_ssp_misc); ++ ++ return 0; ++} ++ ++static const struct of_device_id of_ast_ssp_match_table[] = { ++ { .compatible = "aspeed,ast2600-ssp", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, of_ast_ssp_match_table); ++ ++static struct platform_driver ast_ssp_driver = { ++ .probe = ast_ssp_probe, ++ .remove = ast_ssp_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_ast_ssp_match_table, ++ }, ++}; ++ ++module_platform_driver(ast_ssp_driver); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c +--- a/drivers/soc/aspeed/aspeed-uart-routing.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-uart-routing.c 2026-09-09 15:51:44.719238056 +0000 +@@ -15,20 +15,30 @@ + #define HICRA 0x9c + + /* attributes options */ ++#define UART_ROUTING_IO0 "io0" + #define UART_ROUTING_IO1 "io1" + #define UART_ROUTING_IO2 "io2" + #define UART_ROUTING_IO3 "io3" + #define UART_ROUTING_IO4 "io4" + #define UART_ROUTING_IO5 "io5" + #define UART_ROUTING_IO6 "io6" ++#define UART_ROUTING_IO7 "io7" ++#define UART_ROUTING_IO8 "io8" ++#define UART_ROUTING_IO9 "io9" + #define UART_ROUTING_IO10 "io10" ++#define UART_ROUTING_IO12 "io12" ++#define UART_ROUTING_UART0 "uart0" + #define UART_ROUTING_UART1 "uart1" + #define UART_ROUTING_UART2 "uart2" + #define UART_ROUTING_UART3 "uart3" + #define UART_ROUTING_UART4 "uart4" + #define UART_ROUTING_UART5 "uart5" + #define UART_ROUTING_UART6 "uart6" ++#define UART_ROUTING_UART7 "uart7" ++#define UART_ROUTING_UART8 "uart8" ++#define UART_ROUTING_UART9 "uart9" + #define UART_ROUTING_UART10 "uart10" ++#define UART_ROUTING_UART12 "uart12" + #define UART_ROUTING_RES "reserved" + + struct aspeed_uart_routing { +@@ -488,6 +498,416 @@ + .attrs = ast2600_uart_routing_attrs, + }; + ++/* routing selector for AST27xx node 0 */ ++static struct aspeed_uart_routing_selector ast2700n0_uart9_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART9), ++ .reg = HICR9, ++ .shift = 12, ++ .mask = 0xf, ++ .options = { ++ UART_ROUTING_IO9, ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_RES, ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART12, ++ NULL, ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector ast2700n0_io9_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO9), ++ .reg = HICR9, ++ .shift = 8, ++ .mask = 0xf, ++ .options = { ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART12, ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_RES, ++ UART_ROUTING_UART9, ++ NULL, ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector ast2700n0_uart3_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART3), ++ .reg = HICRA, ++ .shift = 25, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO3, ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO2, ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+ ret = aspeed_mctp_irq_init(priv); -+ if (ret) { -+ dev_err(priv->dev, "Failed to init IRQ!\n"); -+ goto out_dma; -+ } -+ aspeed_mctp_pcie_setup(priv); ++static struct aspeed_uart_routing_selector ast2700n0_uart2_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART2), ++ .reg = HICRA, ++ .shift = 22, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+ name = devm_kasprintf(priv->dev, GFP_KERNEL, "peci-mctp%d", id); -+ priv->peci_mctp = -+ platform_device_register_data(priv->dev, name, PLATFORM_DEVID_NONE, NULL, 0); -+ if (IS_ERR(priv->peci_mctp)) -+ dev_err(priv->dev, "Failed to register peci-mctp device\n"); ++static struct aspeed_uart_routing_selector ast2700n0_uart1_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART1), ++ .reg = HICRA, ++ .shift = 19, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_IO0, ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART0, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+ return 0; ++static struct aspeed_uart_routing_selector ast2700n0_uart0_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART0), ++ .reg = HICRA, ++ .shift = 16, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+out_dma: -+ aspeed_mctp_dma_fini(priv); -+out_drv: -+ aspeed_mctp_drv_fini(priv); -+out: -+ dev_err(&pdev->dev, "Failed to probe Aspeed MCTP: %d\n", ret); -+ return ret; -+} ++static struct aspeed_uart_routing_selector ast2700n0_io3_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO3), ++ .reg = HICRA, ++ .shift = 9, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART9, ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+static void aspeed_mctp_remove(struct platform_device *pdev) -+{ -+ struct aspeed_mctp *priv = platform_get_drvdata(pdev); ++static struct aspeed_uart_routing_selector ast2700n0_io2_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO2), ++ .reg = HICRA, ++ .shift = 6, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART9, ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_IO0, ++ UART_ROUTING_IO1, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+ mctp_pcie_vdm_remove_dev(priv->ndev); -+#endif ++static struct aspeed_uart_routing_selector ast2700n0_io1_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO1), ++ .reg = HICRA, ++ .shift = 3, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART9, ++ UART_ROUTING_UART0, ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+ platform_device_unregister(priv->peci_mctp); ++static struct aspeed_uart_routing_selector ast2700n0_io0_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO0), ++ .reg = HICRA, ++ .shift = 0, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART0, ++ UART_ROUTING_UART1, ++ UART_ROUTING_UART2, ++ UART_ROUTING_UART3, ++ UART_ROUTING_UART9, ++ UART_ROUTING_IO2, ++ UART_ROUTING_IO3, ++ UART_ROUTING_IO9, ++ NULL, ++ }, ++}; + -+ misc_deregister(&priv->mctp_miscdev); ++static struct attribute *ast2700n0_uart_routing_attrs[] = { ++ &ast2700n0_uart9_sel.dev_attr.attr, ++ &ast2700n0_io9_sel.dev_attr.attr, ++ &ast2700n0_uart3_sel.dev_attr.attr, ++ &ast2700n0_uart2_sel.dev_attr.attr, ++ &ast2700n0_uart1_sel.dev_attr.attr, ++ &ast2700n0_uart0_sel.dev_attr.attr, ++ &ast2700n0_io3_sel.dev_attr.attr, ++ &ast2700n0_io2_sel.dev_attr.attr, ++ &ast2700n0_io1_sel.dev_attr.attr, ++ &ast2700n0_io0_sel.dev_attr.attr, ++ NULL, ++}; + -+ aspeed_mctp_irq_disable(priv); ++static const struct attribute_group ast2700n0_uart_routing_attr_group = { ++ .attrs = ast2700n0_uart_routing_attrs, ++}; + -+ aspeed_mctp_dma_fini(priv); ++/* routing selector for AST27xx node 1 */ ++static struct aspeed_uart_routing_selector ast2700n1_uart10_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART10), ++ .reg = HICR9, ++ .shift = 12, ++ .mask = 0xf, ++ .options = { ++ UART_ROUTING_IO10, ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_RES, ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART12, ++ NULL, ++ }, ++}; + -+ aspeed_mctp_drv_fini(priv); -+} ++static struct aspeed_uart_routing_selector ast2700n1_io10_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO10), ++ .reg = HICR9, ++ .shift = 8, ++ .mask = 0xf, ++ .options = { ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART12, ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_RES, ++ UART_ROUTING_UART10, ++ NULL, ++ }, ++}; + -+static const struct aspeed_mctp_match_data ast2500_mctp_match_data = { -+ .rx_cmd_size = sizeof(struct aspeed_mctp_rx_cmd), -+ .tx_cmd_size = sizeof(struct aspeed_mctp_tx_cmd), -+ .packet_unit_size = 128, -+ .need_address_mapping = true, -+ .vdm_hdr_direct_xfer = false, -+ .fifo_auto_surround = false, ++static struct aspeed_uart_routing_selector ast2700n1_uart8_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART8), ++ .reg = HICRA, ++ .shift = 25, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO8, ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO7, ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_IO10, ++ NULL, ++ }, +}; + -+static const struct aspeed_mctp_match_data ast2600_mctp_match_data = { -+ .rx_cmd_size = sizeof(u32), -+ .tx_cmd_size = sizeof(struct aspeed_mctp_tx_cmd), -+ .packet_unit_size = sizeof(struct mctp_pcie_packet_data), -+ .need_address_mapping = false, -+ .vdm_hdr_direct_xfer = true, -+ .fifo_auto_surround = true, ++static struct aspeed_uart_routing_selector ast2700n1_uart7_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART7), ++ .reg = HICRA, ++ .shift = 22, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_IO10, ++ NULL, ++ }, +}; + -+static const struct aspeed_mctp_match_data ast2700_mctp0_match_data = { -+ .rx_cmd_size = sizeof(struct aspeed_mctp_rx_cmd), -+ .tx_cmd_size = sizeof(struct aspeed_g7_mctp_tx_cmd), -+ .packet_unit_size = sizeof(struct mctp_pcie_packet_data), -+ .need_address_mapping = false, -+ .vdm_hdr_direct_xfer = true, -+ .fifo_auto_surround = true, -+ .dma_need_64bits_width = true, -+ .scu_pcie_ctrl_offset = ASPEED_G7_SCU_PCIE0_CTRL_OFFSET, ++static struct aspeed_uart_routing_selector ast2700n1_uart6_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART6), ++ .reg = HICRA, ++ .shift = 19, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_IO5, ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART5, ++ UART_ROUTING_IO10, ++ NULL, ++ }, +}; + -+static const struct aspeed_mctp_match_data ast2700_mctp1_match_data = { -+ .rx_cmd_size = sizeof(struct aspeed_mctp_rx_cmd), -+ .tx_cmd_size = sizeof(struct aspeed_g7_mctp_tx_cmd), -+ .packet_unit_size = sizeof(struct mctp_pcie_packet_data), -+ .need_address_mapping = false, -+ .vdm_hdr_direct_xfer = true, -+ .fifo_auto_surround = true, -+ .dma_need_64bits_width = true, -+ .scu_pcie_ctrl_offset = ASPEED_G7_SCU_PCIE1_CTRL_OFFSET, ++static struct aspeed_uart_routing_selector ast2700n1_uart5_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART5), ++ .reg = HICRA, ++ .shift = 16, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_IO10, ++ NULL, ++ }, +}; + -+static const struct of_device_id aspeed_mctp_match_table[] = { -+ { .compatible = "aspeed,ast2500-mctp", .data = &ast2500_mctp_match_data}, -+ { .compatible = "aspeed,ast2600-mctp", .data = &ast2600_mctp_match_data}, -+ { .compatible = "aspeed,ast2700-mctp0", .data = &ast2700_mctp0_match_data}, -+ { .compatible = "aspeed,ast2700-mctp1", .data = &ast2700_mctp1_match_data}, -+ { } ++static struct aspeed_uart_routing_selector ast2700n1_io8_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO8), ++ .reg = HICRA, ++ .shift = 9, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART10, ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO10, ++ NULL, ++ }, +}; + -+static struct platform_driver aspeed_mctp_driver = { -+ .driver = { -+ .name = "aspeed-mctp", -+ .of_match_table = of_match_ptr(aspeed_mctp_match_table), -+ }, -+ .probe = aspeed_mctp_probe, -+ .remove = aspeed_mctp_remove, ++static struct aspeed_uart_routing_selector ast2700n1_io7_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO7), ++ .reg = HICRA, ++ .shift = 6, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART10, ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_IO5, ++ UART_ROUTING_IO6, ++ UART_ROUTING_IO10, ++ NULL, ++ }, +}; + -+static int __init aspeed_mctp_init(void) -+{ -+ packet_cache = -+ kmem_cache_create_usercopy("mctp-packet", -+ sizeof(struct mctp_pcie_packet), -+ 0, 0, 0, -+ sizeof(struct mctp_pcie_packet), -+ NULL); -+ if (!packet_cache) -+ return -ENOMEM; ++static struct aspeed_uart_routing_selector ast2700n1_io6_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO6), ++ .reg = HICRA, ++ .shift = 3, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART10, ++ UART_ROUTING_UART5, ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_IO10, ++ NULL, ++ }, ++}; + -+ return platform_driver_register(&aspeed_mctp_driver); -+} ++static struct aspeed_uart_routing_selector ast2700n1_io5_sel = { ++ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO5), ++ .reg = HICRA, ++ .shift = 0, ++ .mask = 0x7, ++ .options = { ++ UART_ROUTING_UART5, ++ UART_ROUTING_UART6, ++ UART_ROUTING_UART7, ++ UART_ROUTING_UART8, ++ UART_ROUTING_UART10, ++ UART_ROUTING_IO7, ++ UART_ROUTING_IO8, ++ UART_ROUTING_IO10, ++ NULL, ++ }, ++}; + -+static void __exit aspeed_mctp_exit(void) -+{ -+ platform_driver_unregister(&aspeed_mctp_driver); -+ kmem_cache_destroy(packet_cache); -+} ++static struct attribute *ast2700n1_uart_routing_attrs[] = { ++ &ast2700n1_uart10_sel.dev_attr.attr, ++ &ast2700n1_io10_sel.dev_attr.attr, ++ &ast2700n1_uart8_sel.dev_attr.attr, ++ &ast2700n1_uart7_sel.dev_attr.attr, ++ &ast2700n1_uart6_sel.dev_attr.attr, ++ &ast2700n1_uart5_sel.dev_attr.attr, ++ &ast2700n1_io8_sel.dev_attr.attr, ++ &ast2700n1_io7_sel.dev_attr.attr, ++ &ast2700n1_io6_sel.dev_attr.attr, ++ &ast2700n1_io5_sel.dev_attr.attr, ++ NULL, ++}; + -+module_init(aspeed_mctp_init) -+module_exit(aspeed_mctp_exit) ++static const struct attribute_group ast2700n1_uart_routing_attr_group = { ++ .attrs = ast2700n1_uart_routing_attrs, ++}; + -+MODULE_DEVICE_TABLE(of, aspeed_mctp_match_table); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Iwona Winiarska "); -+MODULE_DESCRIPTION("Aspeed MCTP driver"); -diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c ---- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c 2025-12-23 10:16:21.124032669 +0000 -@@ -431,7 +431,7 @@ - .of_match_table = aspeed_p2a_ctrl_match, - }, - .probe = aspeed_p2a_ctrl_probe, -- .remove_new = aspeed_p2a_ctrl_remove, -+ .remove = aspeed_p2a_ctrl_remove, + static ssize_t aspeed_uart_routing_show(struct device *dev, + struct device_attribute *attr, + char *buf) +@@ -580,6 +1000,10 @@ + .data = &ast2500_uart_routing_attr_group }, + { .compatible = "aspeed,ast2600-uart-routing", + .data = &ast2600_uart_routing_attr_group }, ++ { .compatible = "aspeed,ast2700n0-uart-routing", ++ .data = &ast2700n0_uart_routing_attr_group }, ++ { .compatible = "aspeed,ast2700n1-uart-routing", ++ .data = &ast2700n1_uart_routing_attr_group }, + { }, }; - module_platform_driver(aspeed_p2a_ctrl_driver); -diff --git a/drivers/soc/aspeed/aspeed-pcie-mmbi.c b/drivers/soc/aspeed/aspeed-pcie-mmbi.c ---- a/drivers/soc/aspeed/aspeed-pcie-mmbi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-pcie-mmbi.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,962 @@ +diff --git a/drivers/soc/aspeed/aspeed-udma.c b/drivers/soc/aspeed/aspeed-udma.c +--- a/drivers/soc/aspeed/aspeed-udma.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-udma.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright (C) ASPEED Technology Inc. -+ -+#include ++/* ++ * Copyright 2020 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include +#include -+#include -+#include -+ -+#include -+#include +#include -+#include -+#include ++#include +#include ++#include ++#include ++#include ++ ++#define DEVICE_NAME "aspeed-udma" ++ ++/* UART DMA registers offset */ ++#define UDMA_TX_DMA_EN 0x000 ++#define UDMA_RX_DMA_EN 0x004 ++#define UDMA_MISC 0x008 ++#define UDMA_MISC_RX_BUFSZ GENMASK(3, 2) ++#define UDMA_MISC_TX_BUFSZ GENMASK(1, 0) ++#define UDMA_TMOUT_TIMER 0x00c ++#define UDMA_TX_DMA_RST 0x020 ++#define UDMA_RX_DMA_RST 0x024 ++#define UDMA_TX_DMA_INT_EN 0x030 ++#define UDMA_TX_DMA_INT_STS 0x034 ++#define UDMA_RX_DMA_INT_EN 0x038 ++#define UDMA_RX_DMA_INT_STS 0x03c + -+#include -+#include ++#define UDMA_CHX_OFF(x) ((x) * 0x20) ++#define UDMA_CHX_TX_RD_PTR(x) (0x040 + UDMA_CHX_OFF(x)) ++#define UDMA_CHX_TX_WR_PTR(x) (0x044 + UDMA_CHX_OFF(x)) ++#define UDMA_CHX_TX_BUF_ADDR(x) (0x048 + UDMA_CHX_OFF(x)) ++#define UDMA_CHX_TX_CTRL(x) (0x04c + UDMA_CHX_OFF(x)) ++#define UDMA_TX_CTRL_BUF_ADDRH GENMASK(10, 8) ++#define UDMA_TX_CTRL_TMOUT_DIS BIT(4) ++#define UDMA_TX_CTRL_BUFSZ GENMASK(3, 0) ++#define UDMA_CHX_RX_RD_PTR(x) (0x050 + UDMA_CHX_OFF(x)) ++#define UDMA_CHX_RX_WR_PTR(x) (0x054 + UDMA_CHX_OFF(x)) ++#define UDMA_CHX_RX_BUF_ADDR(x) (0x058 + UDMA_CHX_OFF(x)) ++#define UDMA_CHX_RX_CTRL(x) (0x05c + UDMA_CHX_OFF(x)) ++#define UDMA_RX_CTRL_BUF_ADDRH GENMASK(10, 8) ++#define UDMA_RX_CTRL_TMOUT_DIS BIT(4) ++#define UDMA_RX_CTRL_BUFSZ GENMASK(1, 0) + -+#include -+#include -+#include -+#include -+#include -+#include ++#define UDMA_MAX_CHANNEL 16 ++#define UDMA_TMOUT 0x200 + -+#include -+#include -+#include -+#include -+#include ++enum aspeed_udma_bufsz_code { ++ UDMA_BUFSZ_CODE_1KB, ++ UDMA_BUFSZ_CODE_4KB, ++ UDMA_BUFSZ_CODE_16KB, ++ UDMA_BUFSZ_CODE_64KB, ++}; + -+#include "aspeed-pcie-mmbi.h" ++struct aspeed_udma_chan { ++ dma_addr_t dma_addr; + -+/* AST2700 E2M */ -+#define ASPEED_E2M_EVENT 0x0D0 -+#define ASPEED_E2M_EVENT_SET 0x0D4 -+#define ASPEED_E2M_EVENT_CLR 0x0D8 -+#define ASPEED_E2M_EVENT_EN 0x0DC -+#define ASPEED_E2M_ADRMAP00 0x100 -+#define ASPEED_E2M_WIRQA0 0x180 -+#define ASPEED_E2M_WIRQV0 0x1C0 -+#define ASPEED_E2M_SPROT_SIDG0 0x210 -+#define ASPEED_E2M_SPROT_CTL0 0x280 -+#define ASPEED_E2M_SPROT_ADR0 0x2C0 ++ u32 rb_sz; + -+/* AST2700 SCU */ -+#define ASPEED_SCU_DECODE_DEV BIT(18) -+#define ASPEED_SCU_INT_EN BIT(23) -+struct aspeed_platform { -+ int (*mmbi_init)(struct platform_device *pdev); ++ aspeed_udma_cb_t cb; ++ void *cb_arg; ++ ++ bool dis_tmout; +}; + -+struct aspeed_pcie_mmbi { ++struct aspeed_udma { + struct device *dev; -+ struct regmap *device; -+ struct regmap *e2m; ++ u8 __iomem *regs; + int irq; -+ const struct aspeed_platform *platform; -+ /* E2M index */ -+ int id; -+ int pid; -+ int scu_bar_offset; -+ int e2m_index; -+ int e2m_h2b_int; -+ -+ /* Memory Mapping */ -+ void __iomem *mem_virt; -+ dma_addr_t mem_phy; -+ phys_addr_t mem_size; -+ -+ struct aspeed_mmbi_channel chan; ++ struct aspeed_udma_chan tx_chs[UDMA_MAX_CHANNEL]; ++ struct aspeed_udma_chan rx_chs[UDMA_MAX_CHANNEL]; ++ spinlock_t lock; +}; + -+static void mmbi_desc_init(struct aspeed_mmbi_channel *chan); ++struct aspeed_udma udma[1]; + -+static u8 mmbi_get_bmc_up(struct aspeed_mmbi_channel *chan) ++static int aspeed_udma_get_bufsz_code(u32 buf_sz) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ switch (buf_sz) { ++ case SZ_1K: ++ return UDMA_BUFSZ_CODE_1KB; ++ case SZ_4K: ++ return UDMA_BUFSZ_CODE_4KB; ++ case SZ_16K: ++ return UDMA_BUFSZ_CODE_16KB; ++ case SZ_64K: ++ return UDMA_BUFSZ_CODE_64KB; ++ default: ++ break; ++ } + -+ return hros.b_up; ++ return -1; +} + -+static u8 mmbi_get_bmc_rdy(struct aspeed_mmbi_channel *chan) ++static u32 aspeed_udma_get_tx_rptr(u32 ch_no) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ -+ return hros.b_rdy; ++ return readl(udma->regs + UDMA_CHX_TX_RD_PTR(ch_no)); +} + -+static u8 mmbi_get_bmc_rst(struct aspeed_mmbi_channel *chan) ++static u32 aspeed_udma_get_rx_wptr(u32 ch_no) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ -+ return hros.b_rst; ++ return readl(udma->regs + UDMA_CHX_RX_WR_PTR(ch_no)); +} + -+static u8 mmbi_get_host_rst(struct aspeed_mmbi_channel *chan) ++static void aspeed_udma_set_ptr(u32 ch_no, u32 ptr, bool is_tx) +{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ -+ return hrws.h_rst; ++ writel(ptr, udma->regs + ++ ((is_tx) ? UDMA_CHX_TX_WR_PTR(ch_no) : UDMA_CHX_RX_RD_PTR(ch_no))); +} + -+static u8 mmbi_get_host_rdy(struct aspeed_mmbi_channel *chan) ++void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr) +{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ -+ return hrws.h_rdy; ++ aspeed_udma_set_ptr(ch_no, wptr, true); +} ++EXPORT_SYMBOL(aspeed_udma_set_tx_wptr); + -+static u8 mmbi_get_host_up(struct aspeed_mmbi_channel *chan) ++void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr) +{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ -+ return hrws.h_up; ++ aspeed_udma_set_ptr(ch_no, rptr, false); +} ++EXPORT_SYMBOL(aspeed_udma_set_rx_rptr); + -+static void mmbi_set_bmc_rst(struct aspeed_mmbi_channel *chan, bool set) ++static int aspeed_udma_free_chan(u32 ch_no, bool is_tx) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b_rst = set; -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+} ++ u32 reg; ++ unsigned long flags; + -+static void mmbi_set_bmc_rdy(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_ros hros; ++ if (ch_no > UDMA_MAX_CHANNEL) ++ return -EINVAL; + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b_rdy = set; -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+} ++ spin_lock_irqsave(&udma->lock, flags); + -+static void mmbi_set_bmc_up(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_ros hros; ++ reg = readl(udma->regs + ++ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); ++ reg &= ~(0x1 << ch_no); + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b_up = set; -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+} ++ writel(reg, udma->regs + ++ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); + -+static void raise_b2h_interrupt(struct aspeed_mmbi_channel *chan) -+{ -+ if (!chan->host_int_en) -+ return; ++ spin_unlock_irqrestore(&udma->lock, flags); + -+ regmap_write(chan->mmbi->e2m, ASPEED_E2M_EVENT_SET, BIT(chan->mmbi->e2m_h2b_int)); ++ return 0; +} + -+static void mmbi_clear_hros(struct aspeed_mmbi_channel *chan) ++int aspeed_udma_free_tx_chan(u32 ch_no) +{ -+ memset_io(chan->hros_vmem, 0, sizeof(struct host_ros)); ++ return aspeed_udma_free_chan(ch_no, true); +} ++EXPORT_SYMBOL(aspeed_udma_free_tx_chan); + -+static void mmbi_clear_hrws(struct aspeed_mmbi_channel *chan) ++int aspeed_udma_free_rx_chan(u32 ch_no) +{ -+ memset_io(chan->hrws_vmem, 0, sizeof(struct host_rws)); ++ return aspeed_udma_free_chan(ch_no, false); +} ++EXPORT_SYMBOL(aspeed_udma_free_rx_chan); + -+static void get_b2h_avail_buf_len(struct aspeed_mmbi_channel *chan, ssize_t *avail_buf_len) ++static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, ++ aspeed_udma_cb_t cb, void *id, ++ bool dis_tmout, bool is_tx) +{ -+ struct device *dev = chan->dev; -+ u32 b2h_rp, b2h_wp; -+ -+ b2h_rp = GET_B2H_READ_POINTER(chan); -+ b2h_wp = GET_B2H_WRITE_POINTER(chan); -+ dev_dbg(dev, "MMBI B2H - b2h_rp: 0x%0x, b2h_wp: 0x%0x\n", b2h_rp, b2h_wp); ++ int retval = 0; ++ int rbsz_code; + -+ if (b2h_wp >= b2h_rp) -+ *avail_buf_len = chan->b2h_cb_size - b2h_wp + b2h_rp; -+ else -+ *avail_buf_len = b2h_rp - b2h_wp; -+} ++ u32 reg; ++ unsigned long flags; ++ struct aspeed_udma_chan *ch; + -+static u8 mmbi_get_state(struct aspeed_mmbi_channel *chan) -+{ -+ u8 state = 0; ++ if (ch_no > UDMA_MAX_CHANNEL) { ++ retval = -EINVAL; ++ goto out; ++ } + -+ state = mmbi_get_bmc_up(chan) << 3; -+ state |= mmbi_get_bmc_rst(chan) << 2; -+ state |= mmbi_get_host_up(chan) << 1; -+ state |= mmbi_get_host_rst(chan); ++ rbsz_code = aspeed_udma_get_bufsz_code(rb_sz); ++ if (rbsz_code < 0) { ++ retval = -EINVAL; ++ goto out; ++ } + -+ return state; -+} ++ spin_lock_irqsave(&udma->lock, flags); + -+static int get_mmbi_header(struct aspeed_mmbi_channel *chan, u32 *data_length, -+ u8 *type, u32 *unread_data_len, u8 *padding) -+{ -+ u32 h2b_wp, h2b_rp, b2h_wp, b2h_rp; -+ struct device *dev = chan->dev; -+ struct mmbi_header header; ++ if (is_tx) { ++ reg = readl(udma->regs + UDMA_TX_DMA_INT_EN); ++ if (reg & (0x1 << ch_no)) { ++ retval = -EBUSY; ++ goto unlock_n_out; ++ } + -+ h2b_wp = GET_H2B_WRITE_POINTER(chan); -+ h2b_rp = GET_H2B_READ_POINTER(chan); -+ b2h_wp = GET_B2H_WRITE_POINTER(chan); -+ b2h_rp = GET_B2H_READ_POINTER(chan); -+ dev_dbg(dev, "MMBI HRWS - h2b_wp: 0x%0x, b2h_rp: 0x%0x\n", h2b_wp, -+ b2h_rp); -+ dev_dbg(dev, "MMBI HROS - b2h_wp: 0x%0x, h2b_rp: 0x%0x\n", b2h_wp, -+ h2b_rp); ++ reg |= (0x1 << ch_no); ++ writel(reg, udma->regs + UDMA_TX_DMA_INT_EN); + -+ if (h2b_wp >= h2b_rp) -+ *unread_data_len = h2b_wp - h2b_rp; -+ else -+ *unread_data_len = chan->h2b_cb_size - h2b_rp + h2b_wp; ++ reg = FIELD_PREP(UDMA_TX_CTRL_BUF_ADDRH, (u64)addr >> 32) | ++ ((dis_tmout) ? UDMA_TX_CTRL_TMOUT_DIS : 0) | ++ FIELD_PREP(UDMA_TX_CTRL_BUFSZ, rbsz_code); ++ writel(reg, udma->regs + UDMA_CHX_TX_CTRL(ch_no)); + -+ if (*unread_data_len < sizeof(struct mmbi_header)) { -+ dev_dbg(dev, "No data to read(%d - %d)\n", h2b_wp, h2b_rp); -+ return -EAGAIN; -+ } ++ writel(addr, udma->regs + UDMA_CHX_TX_BUF_ADDR(ch_no)); ++ } else { ++ reg = readl(udma->regs + UDMA_RX_DMA_INT_EN); ++ if (reg & (0x1 << ch_no)) { ++ retval = -EBUSY; ++ goto unlock_n_out; ++ } + -+ dev_dbg(dev, "READ MMBI header from: 0x%lx\n", -+ (ssize_t)(chan->h2b_cb_vmem + h2b_rp)); ++ reg |= (0x1 << ch_no); ++ writel(reg, udma->regs + UDMA_RX_DMA_INT_EN); + -+ /* Extract MMBI protocol - protocol type and length */ -+ if ((h2b_rp + sizeof(header)) <= chan->h2b_cb_size) { -+ memcpy_fromio(&header, chan->h2b_cb_vmem + h2b_rp, -+ sizeof(header)); -+ } else { -+ ssize_t chunk_len = chan->h2b_cb_size - h2b_rp; ++ reg = FIELD_PREP(UDMA_RX_CTRL_BUF_ADDRH, (u64)addr >> 32) | ++ ((dis_tmout) ? UDMA_RX_CTRL_TMOUT_DIS : 0) | ++ FIELD_PREP(UDMA_RX_CTRL_BUFSZ, rbsz_code); ++ writel(reg, udma->regs + UDMA_CHX_RX_CTRL(ch_no)); + -+ memcpy_fromio(&header, chan->h2b_cb_vmem + h2b_rp, chunk_len); -+ memcpy_fromio(((u8 *)&header) + chunk_len, chan->h2b_cb_vmem, -+ sizeof(header) - chunk_len); ++ writel(addr, udma->regs + UDMA_CHX_RX_BUF_ADDR(ch_no)); + } + -+ *data_length = (header.pkt_len << 2) - sizeof(header) - header.pkt_pad; -+ *padding = header.pkt_pad; -+ *type = header.pkt_type; ++ ch = (is_tx) ? &udma->tx_chs[ch_no] : &udma->rx_chs[ch_no]; ++ ch->rb_sz = rb_sz; ++ ch->cb = cb; ++ ch->cb_arg = id; ++ ch->dma_addr = addr; ++ ch->dis_tmout = dis_tmout; + ++unlock_n_out: ++ spin_unlock_irqrestore(&udma->lock, flags); ++out: + return 0; +} + -+static int mmbi_state_check(struct aspeed_mmbi_channel *chan) ++int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, ++ aspeed_udma_cb_t cb, void *id, bool dis_tmout) +{ -+ enum mmbi_state current_state = mmbi_get_state(chan); -+ struct device *dev = chan->dev; -+ u32 req_data_len, unread_data_len; -+ u8 type, padding; -+ -+ switch (current_state) { -+ case INIT_MISMATCH: -+ dev_dbg(dev, "Get INIT_MISMATCH state from HOST"); -+ /* Reset MMBI data structure */ -+ mmbi_desc_init(chan); -+ /* Translat state to INIT_IN_PROGRESS */ -+ mmbi_clear_hros(chan); -+ mmbi_clear_hrws(chan); -+ /* Translat state to INIT_COMPLETED*/ -+ mmbi_set_bmc_up(chan, 1); -+ -+ dev_dbg(dev, "Change state to INIT_COMPLETED to HOST"); -+ raise_b2h_interrupt(chan); -+ return 1; -+ case NORMAL_RUNTIME: -+ if (mmbi_get_bmc_rdy(chan)) -+ return 0; -+ dev_dbg(dev, "Get NORMAL_RUNTIME state from HOST"); -+ mmbi_set_bmc_rdy(chan, 1); -+ return 1; -+ case RESET_REQ_BY_HOST: -+ dev_dbg(dev, "Get RESET_REQ_BY_HOST state from HOST"); -+ /* Stop operation */ -+ mmbi_set_bmc_rdy(chan, 0); -+ /* Change state to RESET_ACKED */ -+ mmbi_set_bmc_rst(chan, 1); -+ raise_b2h_interrupt(chan); -+ /* Change state to TRANS_TO_INIT */ -+ mmbi_set_bmc_up(chan, 0); -+ /* Reset MMBI data structure */ -+ mmbi_desc_init(chan); -+ /* Translat state to INIT_IN_PROGRESS */ -+ mmbi_clear_hros(chan); -+ mmbi_clear_hrws(chan); -+ /* Translat state to INIT_COMPLETED*/ -+ mmbi_set_bmc_up(chan, 1); -+ -+ dev_dbg(dev, "Change state to INIT_COMPLETED to HOST"); -+ raise_b2h_interrupt(chan); -+ return 1; -+ case RESET_ACKED: -+ /* Receive all packet from Host */ -+ while (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) == 0 && -+ mmbi_get_state(chan) == RESET_ACKED) -+ ; -+ /* Change state to TRANS_TO_INIT */ -+ mmbi_set_bmc_up(chan, 0); -+ /* Reset MMBI data structure */ -+ mmbi_desc_init(chan); -+ /* Translat state to INIT_IN_PROGRESS */ -+ mmbi_clear_hros(chan); -+ mmbi_clear_hrws(chan); -+ /* Translat state to INIT_COMPLETED*/ -+ mmbi_set_bmc_up(chan, 1); -+ -+ dev_dbg(dev, "Change state to INIT_COMPLETED to HOST"); -+ raise_b2h_interrupt(chan); -+ default: -+ break; -+ } -+ -+ return 0; ++ return aspeed_udma_request_chan(ch_no, addr, rb_sz, cb, id, ++ dis_tmout, true); +} ++EXPORT_SYMBOL(aspeed_udma_request_tx_chan); + -+static void update_host_ros(struct aspeed_mmbi_channel *chan, unsigned int w_len, -+ unsigned int r_len) ++int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, ++ aspeed_udma_cb_t cb, void *id, bool dis_tmout) +{ -+ struct device *dev = chan->dev; -+ struct host_ros hros; -+ u32 h2b_rp, b2h_wp; -+ -+ b2h_wp = GET_B2H_WRITE_POINTER(chan); -+ h2b_rp = GET_H2B_READ_POINTER(chan); -+ -+ /* Advance the B2H CB offset for next write */ -+ if ((b2h_wp + w_len) <= chan->b2h_cb_size) -+ b2h_wp += w_len; -+ else -+ b2h_wp = b2h_wp + w_len - chan->b2h_cb_size; -+ -+ /* Advance the H2B CB offset till where BMC read data */ -+ if ((h2b_rp + r_len) <= chan->h2b_cb_size) -+ h2b_rp += r_len; -+ else -+ h2b_rp = h2b_rp + r_len - chan->h2b_cb_size; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b2h_wp = FIELD_GET(B2H_WRITE_POINTER_MASK, b2h_wp); -+ hros.h2b_rp = FIELD_GET(H2B_READ_POINTER_MASK, h2b_rp); -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+ dev_dbg(dev, "Updating HROS - h2b_rp: 0x%0x, b2h_wp: 0x%0x\n", h2b_rp, b2h_wp); -+ -+ if (w_len != 0) -+ raise_b2h_interrupt(chan); ++ return aspeed_udma_request_chan(ch_no, addr, rb_sz, cb, id, ++ dis_tmout, false); +} ++EXPORT_SYMBOL(aspeed_udma_request_rx_chan); + -+static int aspeed_mmbi_write(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, -+ protocol_type type) ++static void aspeed_udma_chan_ctrl(u32 ch_no, u32 op, bool is_tx) +{ -+ struct device *dev = chan->dev; -+ struct mmbi_header header = { 0 }; -+ ssize_t avail_buf_len; -+ ssize_t total_len; -+ ssize_t wt_offset; -+ ssize_t chunk_len; -+ ssize_t end_offset; -+ u8 padding = 0; -+ -+ /* If HOST READY bit is not set, Just discard the write. */ -+ if (!GET_HOST_READY_BIT(chan)) { -+ dev_dbg(dev, "Host not ready, discarding request...\n"); -+ return -EAGAIN; -+ } -+ -+ get_b2h_avail_buf_len(chan, &avail_buf_len); -+ -+ dev_dbg(dev, "B2H buffer empty space: %ld\n", avail_buf_len); -+ -+ /* Header size */ -+ total_len = len + 4; ++ unsigned long flags; ++ u32 reg_en, reg_rst; ++ u32 reg_en_off = (is_tx) ? UDMA_TX_DMA_EN : UDMA_RX_DMA_EN; ++ u32 reg_rst_off = (is_tx) ? UDMA_TX_DMA_RST : UDMA_TX_DMA_RST; + -+ padding = total_len & 0x3; -+ if (padding) -+ padding = 4 - padding; -+ total_len += padding; ++ if (ch_no > UDMA_MAX_CHANNEL) ++ return; + -+ /* Empty space should be more than write request data size */ -+ if (avail_buf_len <= sizeof(header) || (total_len > (avail_buf_len - sizeof(header)))) -+ return -ENOSPC; ++ spin_lock_irqsave(&udma->lock, flags); + -+ /* Fill multi-protocol header */ -+ header.pkt_type = type; -+ header.pkt_len = total_len >> 2; -+ header.pkt_pad = padding; ++ reg_en = readl(udma->regs + reg_en_off); ++ reg_rst = readl(udma->regs + reg_rst_off); + -+ wt_offset = GET_B2H_WRITE_POINTER(chan); -+ end_offset = chan->b2h_cb_size; ++ switch (op) { ++ case ASPEED_UDMA_OP_ENABLE: ++ reg_en |= (0x1 << ch_no); ++ writel(reg_en, udma->regs + reg_en_off); ++ break; ++ case ASPEED_UDMA_OP_DISABLE: ++ reg_en &= ~(0x1 << ch_no); ++ writel(reg_en, udma->regs + reg_en_off); ++ break; ++ case ASPEED_UDMA_OP_RESET: ++ reg_en &= ~(0x1 << ch_no); ++ writel(reg_en, udma->regs + reg_en_off); + -+ /* Copy Header */ -+ if ((end_offset - wt_offset) >= sizeof(header)) { -+ memcpy_toio(chan->b2h_cb_vmem + wt_offset, &header, sizeof(header)); -+ wt_offset += sizeof(header); -+ } else { -+ chunk_len = end_offset - wt_offset; -+ memcpy_toio(chan->b2h_cb_vmem + wt_offset, &header, chunk_len); -+ memcpy_toio(chan->b2h_cb_vmem, &header + chunk_len, (sizeof(header) - chunk_len)); -+ wt_offset = (sizeof(header) - chunk_len); -+ } ++ reg_rst |= (0x1 << ch_no); ++ writel(reg_rst, udma->regs + reg_rst_off); + -+ /* Write the data */ -+ if ((end_offset - wt_offset) >= len) { -+ memcpy_toio(&chan->b2h_cb_vmem[wt_offset], buffer, len); -+ wt_offset += len; -+ } else { -+ chunk_len = end_offset - wt_offset; -+ dev_dbg(dev, "Write data chunk_len: %ld\n", chunk_len); -+ memcpy_toio(&chan->b2h_cb_vmem[wt_offset], buffer, chunk_len); ++ udelay(100); + -+ wt_offset = 0; -+ memcpy_toio(&chan->b2h_cb_vmem[wt_offset], buffer + chunk_len, len - chunk_len); -+ wt_offset += len - chunk_len; ++ reg_rst &= ~(0x1 << ch_no); ++ writel(reg_rst, udma->regs + reg_rst_off); ++ break; ++ default: ++ break; + } + -+ update_host_ros(chan, total_len, 0); -+ -+ return 0; ++ spin_unlock_irqrestore(&udma->lock, flags); +} + -+static void aspeed_mmbi_read(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, u8 padding) ++void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) +{ -+ struct device *dev = chan->dev; -+ ssize_t rd_offset; -+ u32 h2b_rp; -+ -+ h2b_rp = GET_H2B_READ_POINTER(chan); -+ if ((h2b_rp + sizeof(struct mmbi_header)) <= chan->h2b_cb_size) -+ rd_offset = h2b_rp + sizeof(struct mmbi_header); -+ else -+ rd_offset = h2b_rp + sizeof(struct mmbi_header) - chan->h2b_cb_size; -+ -+ /* Extract data and copy to user space application */ -+ dev_dbg(dev, "READ MMBI Data from: 0x%0lx and length: %ld\n", -+ (ssize_t)(chan->h2b_cb_vmem + rd_offset), len); -+ -+ if ((chan->h2b_cb_size - rd_offset) >= len) { -+ memcpy_fromio(buffer, chan->h2b_cb_vmem + rd_offset, len); -+ rd_offset += len; -+ } else { -+ ssize_t chunk_len; -+ -+ chunk_len = chan->h2b_cb_size - rd_offset; -+ dev_dbg(dev, "Read data chunk_len: %ld\n", chunk_len); -+ memcpy_fromio(buffer, chan->h2b_cb_vmem + rd_offset, chunk_len); -+ -+ rd_offset = 0; -+ memcpy_fromio(buffer + chunk_len, chan->h2b_cb_vmem + rd_offset, len - chunk_len); -+ } ++ aspeed_udma_chan_ctrl(ch_no, op, true); ++} ++EXPORT_SYMBOL(aspeed_udma_tx_chan_ctrl); + -+ update_host_ros(chan, 0, len + sizeof(struct mmbi_header) + padding); ++void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) ++{ ++ aspeed_udma_chan_ctrl(ch_no, op, false); +} ++EXPORT_SYMBOL(aspeed_udma_rx_chan_ctrl); + -+static void mctp_mmbi_rx(struct aspeed_mmbi_channel *chan) ++static irqreturn_t aspeed_udma_isr(int irq, void *arg) +{ -+ struct net_device *ndev = chan->ndev; -+ struct sk_buff *skb; -+ struct mctp_skb_cb *cb; -+ u32 req_data_len, unread_data_len; -+ u8 type, padding; -+ int status; ++ u32 bit; ++ unsigned long tx_sts = readl(udma->regs + UDMA_TX_DMA_INT_STS); ++ unsigned long rx_sts = readl(udma->regs + UDMA_RX_DMA_INT_STS); + -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; ++ if (udma != (struct aspeed_udma *)arg) ++ return IRQ_NONE; + -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d, Unread data: %d\n", __func__, -+ req_data_len, type, unread_data_len); ++ if (tx_sts == 0 && rx_sts == 0) ++ return IRQ_NONE; + -+ skb = netdev_alloc_skb(ndev, req_data_len); -+ if (!skb) { -+ ndev->stats.rx_dropped++; -+ update_host_ros(chan, 0, req_data_len + sizeof(struct mmbi_header)); -+ return; ++ for_each_set_bit(bit, &tx_sts, UDMA_MAX_CHANNEL) { ++ writel((0x1 << bit), udma->regs + UDMA_TX_DMA_INT_STS); ++ if (udma->tx_chs[bit].cb) ++ udma->tx_chs[bit].cb(aspeed_udma_get_tx_rptr(bit), ++ udma->tx_chs[bit].cb_arg); + } + -+ skb->protocol = htons(ETH_P_MCTP); -+ aspeed_mmbi_read(chan, skb_put(skb, req_data_len), req_data_len, padding); -+ skb_reset_network_header(skb); -+ -+ cb = __mctp_cb(skb); -+ cb->halen = 0; -+ -+ status = netif_rx(skb); -+ if (status == NET_RX_SUCCESS) { -+ ndev->stats.rx_packets++; -+ ndev->stats.rx_bytes += req_data_len; -+ } else { -+ ndev->stats.rx_dropped++; ++ for_each_set_bit(bit, &rx_sts, UDMA_MAX_CHANNEL) { ++ writel((0x1 << bit), udma->regs + UDMA_RX_DMA_INT_STS); ++ if (udma->rx_chs[bit].cb) ++ udma->rx_chs[bit].cb(aspeed_udma_get_rx_wptr(bit), ++ udma->rx_chs[bit].cb_arg); + } ++ ++ return IRQ_HANDLED; +} + -+static netdev_tx_t mctp_mmbi_tx(struct sk_buff *skb, struct net_device *ndev) ++static int aspeed_udma_probe(struct platform_device *pdev) +{ -+ struct aspeed_mmbi_mctp *mctp = netdev_priv(ndev); -+ int ret; ++ int i, rc; ++ uint32_t reg; ++ struct resource *res; ++ struct device *dev = &pdev->dev; + -+ if (!mmbi_get_host_rdy(&mctp->mmbi->chan) || skb->len > MCTP_MMBI_MTU_MAX) { -+ ndev->stats.tx_dropped++; -+ goto out; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (IS_ERR_OR_NULL(res)) { ++ dev_err(dev, "failed to get register base\n"); ++ return -ENODEV; + } + -+ ret = aspeed_mmbi_write(&mctp->mmbi->chan, skb->data, skb->len, MMBI_PROTOCOL_MCTP); -+ if (ret) { -+ netif_stop_queue(ndev); -+ return NETDEV_TX_BUSY; ++ udma->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR_OR_NULL(udma->regs)) { ++ dev_err(dev, "failed to map registers\n"); ++ return PTR_ERR(udma->regs); + } + -+ ndev->stats.tx_packets++; -+ ndev->stats.tx_bytes += skb->len; -+out: -+ kfree_skb(skb); -+ return NETDEV_TX_OK; -+} ++ /* disable for safety */ ++ writel(0x0, udma->regs + UDMA_TX_DMA_EN); ++ writel(0x0, udma->regs + UDMA_RX_DMA_EN); + -+static const struct net_device_ops mctp_mmbi_netdev_ops = { -+ .ndo_start_xmit = mctp_mmbi_tx, -+}; ++ udma->irq = platform_get_irq(pdev, 0); ++ if (udma->irq < 0) { ++ dev_err(dev, "failed to get IRQ number\n"); ++ return -ENODEV; ++ } + -+static void aspeed_mctp_mmbi_setup(struct net_device *ndev) -+{ -+ ndev->type = ARPHRD_MCTP; ++ rc = devm_request_irq(dev, udma->irq, aspeed_udma_isr, ++ IRQF_SHARED, DEVICE_NAME, udma); ++ if (rc) { ++ dev_err(dev, "failed to request IRQ handler\n"); ++ return rc; ++ } + -+ /* we limit at the fixed MTU, which is also the MCTP-standard -+ * baseline MTU, so is also our minimum ++ /* ++ * For legacy design. ++ * - TX ringbuffer size: 4KB ++ * - RX ringbuffer size: 64KB ++ * - Timeout timer disabled + */ -+ ndev->mtu = MCTP_MMBI_MTU; -+ ndev->max_mtu = MCTP_MMBI_MTU_MAX; -+ ndev->min_mtu = MCTP_MMBI_MTU_MIN; -+ -+ ndev->hard_header_len = 0; -+ ndev->addr_len = 0; -+ ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; -+ ndev->flags = IFF_NOARP; -+ ndev->netdev_ops = &mctp_mmbi_netdev_ops; -+ ndev->needs_free_netdev = true; -+} -+ -+static int aspeed_mmbi_mctp_init(struct aspeed_mmbi_channel *chan) -+{ -+ struct aspeed_mmbi_mctp *mctp; -+ struct net_device *ndev; -+ char name[32]; -+ int ret; -+ -+ snprintf(name, sizeof(name), "mctpmmbi%d%d", chan->mmbi->id, chan->mmbi->e2m_index); -+ ndev = alloc_netdev(sizeof(*mctp), name, NET_NAME_ENUM, aspeed_mctp_mmbi_setup); -+ if (!ndev) -+ return -ENOMEM; -+ -+ mctp = netdev_priv(ndev); -+ mctp->ndev = ndev; -+ mctp->mmbi = chan->mmbi; -+ -+ chan->ndev = ndev; -+ -+ ret = register_netdev(ndev); -+ if (ret) -+ goto free_netdev; -+ -+ return 0; -+ -+free_netdev: -+ free_netdev(ndev); -+ -+ return ret; -+} -+ -+static void aspeed_mmbi_work_func(struct work_struct *workq) -+{ -+ struct aspeed_mmbi_channel *chan = container_of(workq, struct aspeed_mmbi_channel, work); -+ u32 weight = 256, req_data_len, unread_data_len; -+ u8 type, padding; -+ int i; -+ -+ for (i = 0; i < weight; i++) { -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; -+ -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d\n", -+ __func__, req_data_len, type); -+ -+ if (type == MMBI_PROTOCOL_MCTP) -+ mctp_mmbi_rx(chan); -+ else -+ /* Discard data and advance the hrws */ -+ update_host_ros(chan, 0, req_data_len + sizeof(struct mmbi_header) + padding); ++ reg = FIELD_PREP(UDMA_MISC_TX_BUFSZ, UDMA_BUFSZ_CODE_4KB) | ++ FIELD_PREP(UDMA_MISC_RX_BUFSZ, UDMA_BUFSZ_CODE_64KB); ++ writel(reg, udma->regs + UDMA_MISC); + -+ raise_b2h_interrupt(chan); ++ for (i = 0; i < UDMA_MAX_CHANNEL; ++i) { ++ writel(0, udma->regs + UDMA_CHX_TX_WR_PTR(i)); ++ writel(0, udma->regs + UDMA_CHX_RX_RD_PTR(i)); + } + -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ queue_work(system_unbound_wq, &chan->work); -+} -+ -+static irqreturn_t aspeed_pcie_mmbi_isr(int irq, void *dev_id) -+{ -+ struct aspeed_pcie_mmbi *mmbi = dev_id; -+ struct aspeed_mmbi_channel *chan = &mmbi->chan; -+ ssize_t avail_buf_len; -+ -+ get_b2h_avail_buf_len(chan, &avail_buf_len); -+ if (avail_buf_len > MCTP_MMBI_MTU_MAX) { -+ if (netif_queue_stopped(chan->ndev)) { -+ dev_dbg(chan->dev, "Wake up mctp net device\n"); -+ netif_wake_queue(chan->ndev); -+ } -+ } ++ writel(0xffffffff, udma->regs + UDMA_TX_DMA_RST); ++ writel(0x0, udma->regs + UDMA_TX_DMA_RST); + -+ if (mmbi_state_check(chan)) -+ return IRQ_HANDLED; ++ writel(0xffffffff, udma->regs + UDMA_RX_DMA_RST); ++ writel(0x0, udma->regs + UDMA_RX_DMA_RST); + -+ queue_work(system_unbound_wq, &chan->work); ++ writel(0x0, udma->regs + UDMA_TX_DMA_INT_EN); ++ writel(0xffffffff, udma->regs + UDMA_TX_DMA_INT_STS); ++ writel(0x0, udma->regs + UDMA_RX_DMA_INT_EN); ++ writel(0xffffffff, udma->regs + UDMA_RX_DMA_INT_STS); + -+ return IRQ_HANDLED; -+} ++ writel(UDMA_TMOUT, udma->regs + UDMA_TMOUT_TIMER); + -+static void mmbi_desc_init(struct aspeed_mmbi_channel *chan) -+{ -+ struct mmbi_cap_desc desc; ++ spin_lock_init(&udma->lock); + -+ memset(&desc, 0, sizeof(struct mmbi_cap_desc)); ++ dev_set_drvdata(dev, udma); + -+ desc.version = 1; -+ /* This MMBI interface is intended for OS use */ -+ desc.os_use = 1; -+ desc.b2h_ba = (chan->b2h_cb_vmem - chan->desc_vmem) >> 3; -+ desc.h2b_ba = (chan->h2b_cb_vmem - chan->desc_vmem) >> 3; -+ /* Make sure the buffer size is 4 byte aligmnent */ -+ desc.b2h_l = chan->b2h_cb_size & ~0x3; -+ desc.h2b_l = chan->h2b_cb_size & ~0x3; -+ /* Variable Packet Size Circular Buffers (VPSCB) v1 */ -+ desc.buffer_type = 0x01; -+ desc.bt_desc.h_ros_p = (chan->hros_vmem - chan->desc_vmem) >> 3; -+ desc.bt_desc.h_rws_p = (chan->hrws_vmem - chan->desc_vmem) >> 3; -+ /* PCIe Interrupt */ -+ desc.bt_desc.h_int_t = 0x01; -+ desc.bt_desc.h_int_l = chan->host_int_location; -+ desc.bt_desc.h_int_v = 0; /* Skip for PCIe Interrupt */ -+ desc.bt_desc.bmc_int_t = 0x01; /* relative memory space address */ -+ desc.bt_desc.bmc_int_l = chan->bmc_int_location; -+ desc.bt_desc.bmc_int_v = chan->bmc_int_value; -+ -+ /* Per MMBI protoco spec, Set it to "#MMBI$" */ -+ memcpy(desc.signature, MMBI_SIGNATURE, sizeof(desc.signature)); -+ -+ memcpy_toio(chan->desc_vmem, &desc, sizeof(desc)); ++ return 0; +} + -+static int aspeed_pcie_mmbi_init(struct aspeed_pcie_mmbi *mmbi) -+{ -+ struct aspeed_mmbi_channel *chan = &mmbi->chan; -+ struct device *dev = chan->dev; -+ u32 b2h_size = mmbi->mem_size >> 1; -+ u32 h2b_size = mmbi->mem_size >> 1; -+ u8 *h2b_vaddr, *b2h_vaddr; -+ int ret; -+ -+ b2h_vaddr = mmbi->mem_virt; -+ h2b_vaddr = b2h_vaddr + b2h_size; -+ -+ chan->dev = dev; -+ chan->desc_vmem = b2h_vaddr; -+ chan->hros_vmem = b2h_vaddr + sizeof(struct mmbi_cap_desc); -+ chan->b2h_cb_vmem = b2h_vaddr + sizeof(struct mmbi_cap_desc) + sizeof(struct host_ros); -+ chan->b2h_cb_size = b2h_size - sizeof(struct mmbi_cap_desc) - sizeof(struct host_ros); -+ -+ chan->hrws_vmem = h2b_vaddr; -+ chan->h2b_cb_vmem = h2b_vaddr + sizeof(struct host_rws); -+ chan->h2b_cb_size = h2b_size - sizeof(struct host_rws); -+ -+ dev_dbg(dev, "B2H mapped addr - desc: 0x%0lx, hros: 0x%0lx, b2h_cb: 0x%0lx\n", -+ (size_t)chan->desc_vmem, (size_t)chan->hros_vmem, (size_t)chan->b2h_cb_vmem); -+ dev_dbg(dev, "H2B mapped addr - hrws: 0x%0lx, h2b_cb: 0x%0lx\n", (size_t)chan->hrws_vmem, -+ (size_t)chan->h2b_cb_vmem); ++static const struct of_device_id aspeed_udma_match[] = { ++ { .compatible = "aspeed,ast2500-udma" }, ++ { .compatible = "aspeed,ast2600-udma" }, ++ { .compatible = "aspeed,ast2700-udma" }, ++ { }, ++}; + -+ dev_dbg(dev, "B2H buffer size: 0x%0lx\n", (size_t)chan->b2h_cb_size); -+ dev_dbg(dev, "H2B buffer size: 0x%0lx\n", (size_t)chan->h2b_cb_size); ++static struct platform_driver aspeed_udma_driver = { ++ .driver = { ++ .name = DEVICE_NAME, ++ .of_match_table = aspeed_udma_match, + -+ /* Initialize the MMBI channel descriptor */ -+ mmbi_desc_init(chan); ++ }, ++ .probe = aspeed_udma_probe, ++}; + -+ /* Clear HRWS & HROS */ -+ mmbi_clear_hros(chan); -+ mmbi_clear_hrws(chan); ++module_platform_driver(aspeed_udma_driver); + -+ /* Initialize MTCP function */ -+ ret = aspeed_mmbi_mctp_init(chan); -+ if (ret) { -+ dev_err(dev, "Unable to init mctp\n"); -+ return ret; -+ } ++MODULE_AUTHOR("Chia-Wei Wang "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Aspeed UDMA Engine Driver"); +diff --git a/drivers/soc/aspeed/aspeed-usb-hp.c b/drivers/soc/aspeed/aspeed-usb-hp.c +--- a/drivers/soc/aspeed/aspeed-usb-hp.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-usb-hp.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2021 Aspeed Technology Inc. ++ */ + -+ /* Set BMC UP bit */ -+ mmbi_set_bmc_up(chan, 1); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ return 0; -+} ++#define USB_HP_BEHCI84 0x84 /* Controller Fine-tune Register */ ++#define USB_HP_BEHCI88 0x88 /* Frame Timing Adjustment */ + ++#define BEHCI_64BIT BIT(11) /* Enable support 64 bit address mode */ ++#define BEHCI_PRE_EOF1(x) ((x) << 12) ++#define BEHCI_PRE_EOF2(x) ((x) << 22) +/* -+ * AST2700 PCIe MMBI (SCU & E2M) -+ * SoC | 0 | 1 | -+ * PCI class | MFD (0xFF_00_00) | MMBI (0x0C_0C_00) | -+ * Node | 0 1 | 0 | -+ * PID | 3 4 5 6 11 12 13 14 | 2 3 4 5 6 7 | -+ * E2M index | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 | -+ * BAR index | 2 3 4 5 2 3 4 5 | 0 1 2 3 4 5 | -+ * SCU BAR | 3c 4c 5c 6c 3c 4c 5c 6c | 1c 50 3c 4c 5c 6c | -+ * E2M H2B Int | 0 1 2 3 0 1 2 3 | 0 1 2 3 4 5 | (bit) ++ * Set preEOF1 to 0x100 and preEOF2 to 0x140 ++ * (i.e. preEOF1 + MPS 0x40) as the workaround. + */ -+static int aspeed_ast2700_pcie_mmbi_init(struct platform_device *pdev) -+{ -+ struct aspeed_pcie_mmbi *mmbi = platform_get_drvdata(pdev); -+ struct aspeed_mmbi_channel *chan = &mmbi->chan; -+ struct device *dev = &pdev->dev; -+ u32 value, sprot_size, e2m_index, pid; -+ struct resource res; -+ int ret, i; ++#define BEHCI_EOF1_EOF2_TIMING \ ++ (BEHCI_PRE_EOF1(0x100) | BEHCI_PRE_EOF2(0x140)) ++ ++static const struct of_device_id aspeed_usb_hp_dt_ids[] = { ++ { ++ .compatible = "aspeed,ast2600-usb2ahp", ++ }, ++ { ++ .compatible = "aspeed,ast2700-usb3hp", ++ }, ++ { ++ .compatible = "aspeed,ast2700-usb2hp", ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, aspeed_usb_hp_dt_ids); + -+ /* Get register map*/ -+ mmbi->e2m = syscon_node_to_regmap(dev->of_node->parent); -+ if (IS_ERR(mmbi->e2m)) { -+ dev_err(dev, "failed to find e2m regmap\n"); -+ return PTR_ERR(mmbi->e2m); -+ } -+ if (of_address_to_resource(dev->of_node->parent, 0, &res)) { -+ dev_err(dev, "Failed to get e2m resource\n"); -+ return -EINVAL; -+ } -+ if (res.start == 0x14c1d000) -+ mmbi->id = 2; -+ else if (res.start == 0x12c22000) -+ mmbi->id = 1; -+ else -+ mmbi->id = 0; /* 0x12c21000 */ ++static int aspeed_usb_hp_probe(struct platform_device *pdev) ++{ ++ void __iomem *regs; ++ u32 val; ++ struct clk *clk; ++ struct reset_control *rst; ++ struct regmap *device; ++ struct phy *usb3_phy; ++ bool is_pcie_xhci; ++ int rc = 0; + -+ mmbi->device = syscon_regmap_lookup_by_phandle(dev->of_node->parent, "aspeed,device"); -+ if (IS_ERR(mmbi->device)) { -+ dev_err(dev, "failed to find device regmap\n"); -+ return PTR_ERR(mmbi->device); ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2600-usb2ahp")) { ++ dev_info(&pdev->dev, "Initialized AST2600 USB2AHP\n"); ++ return 0; + } + -+ ret = of_property_read_u32(dev->of_node, "index", &mmbi->e2m_index); -+ if (ret < 0) { -+ dev_err(dev, "cannot get mmbi index value\n"); -+ return ret; ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2700-usb3hp")) ++ is_pcie_xhci = true; ++ else if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2700-usb2hp")) ++ is_pcie_xhci = false; ++ ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ rc = clk_prepare_enable(clk); ++ if (rc) { ++ dev_err(&pdev->dev, "Unable to enable clock (%d)\n", rc); ++ return rc; + } + -+ ret = of_property_read_u32(dev->of_node, "pid", &mmbi->pid); -+ if (ret < 0) { -+ dev_err(dev, "cannot get mmbi pid value\n"); -+ return ret; ++ rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); ++ if (IS_ERR(rst)) { ++ rc = PTR_ERR(rst); ++ goto err; + } ++ rc = reset_control_deassert(rst); ++ if (rc) ++ goto err; + -+ ret = of_property_read_u32(dev->of_node, "bar", &mmbi->scu_bar_offset); -+ if (ret < 0) { -+ dev_err(dev, "cannot get mmbi bar value\n"); -+ return ret; ++ device = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "aspeed,device"); ++ if (IS_ERR(device)) { ++ dev_err(&pdev->dev, "failed to find device regmap\n"); ++ goto err; + } + -+ e2m_index = mmbi->e2m_index; -+ pid = mmbi->pid; -+ mmbi->e2m_h2b_int += mmbi->e2m_index; -+ if (mmbi->id < 2) { -+ /* PCIe device class, sub-class, protocol and reversion */ -+ regmap_write(mmbi->device, 0x18, 0xFF000027); ++ if (is_pcie_xhci) { ++ usb3_phy = devm_phy_get(&pdev->dev, "usb3-phy"); ++ if (IS_ERR(usb3_phy)) { ++ rc = dev_err_probe(&pdev->dev, PTR_ERR(usb3_phy), ++ "failed to get usb3 phy\n"); ++ goto err; ++ } ++ rc = phy_init(usb3_phy); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "failed to init usb3 phy\n"); ++ goto err; ++ } ++ //EnPCIaMSI_EnPCIaIntA_EnPCIaMst_EnPCIaDev ++ /* Turn on PCIe xHCI without MSI */ ++ regmap_update_bits(device, 0x70, ++ BIT(19) | BIT(11) | BIT(3), ++ BIT(19) | BIT(11) | BIT(3)); + } else { -+ regmap_write(mmbi->device, 0x18, 0x0C0C0027); -+ regmap_write(mmbi->device, 0x78, ASPEED_SCU_INT_EN | ASPEED_SCU_DECODE_DEV); -+ } ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) { ++ dev_err(&pdev->dev, "Failed to map resources\n"); ++ rc = PTR_ERR(regs); ++ goto err; ++ } + -+ /* MSI */ -+ regmap_update_bits(mmbi->device, 0x74, GENMASK(7, 4), BIT(7) | (5 << 4)); ++ if (device_property_read_bool(&pdev->dev, "aspeed,ehci_32bits_cap")) { ++ val = readl(regs + USB_HP_BEHCI84) & ~BEHCI_64BIT; ++ writel(val, regs + USB_HP_BEHCI84); ++ } + -+ regmap_update_bits(mmbi->device, 0x70, BIT(25) | BIT(17) | BIT(9) | BIT(1), -+ BIT(25) | BIT(17) | BIT(9) | BIT(1)); ++ /* Adjust PCIe-EHCI EOF1/EOF2 timing to workaround the DMA termination bug. */ ++ writel(BEHCI_EOF1_EOF2_TIMING, regs + USB_HP_BEHCI88); + -+ /* Calculate the BAR Size */ -+ for (i = 1; i < 16; i++) { -+ /* bar size check for 4k align */ -+ if ((mmbi->mem_size / 4096) == (1 << (i - 1))) -+ break; -+ } -+ if (i == 16) { -+ i = 0; -+ dev_warn(dev, "Bar size not align for 4K : %dK\n", (u32)mmbi->mem_size / 1024); ++ //EnPCIaMSI_EnPCIaIntA_EnPCIaMst_EnPCIaDev ++ /* Turn on PCIe EHCI without MSI */ ++ regmap_update_bits(device, 0x70, ++ BIT(18) | BIT(10) | BIT(2), ++ BIT(18) | BIT(10) | BIT(2)); + } -+ regmap_write(mmbi->device, mmbi->scu_bar_offset, (mmbi->mem_phy >> 4) | i); -+ regmap_write(mmbi->e2m, ASPEED_E2M_ADRMAP00 + (4 * pid), (mmbi->mem_phy >> 4) | i); ++ dev_info(&pdev->dev, "Initialized AST2700 USB Host PCIe %s\n", is_pcie_xhci ? "xHCI" : "EHCI"); ++ return 0; ++err: ++ if (clk) ++ clk_disable_unprepare(clk); ++ return rc; ++} + -+ /* BMC Interrupt */ -+ if (chan->bmc_int_en) { -+ value = mmbi->mem_phy + chan->bmc_int_location; -+ regmap_write(mmbi->e2m, ASPEED_E2M_WIRQA0 + (4 * e2m_index), value); -+ value = (BIT(16) << pid) | chan->bmc_int_value; -+ regmap_write(mmbi->e2m, ASPEED_E2M_WIRQV0 + (4 * e2m_index), value); -+ } -+ -+ /* HOST Interrupt: MSI */ -+ regmap_read(mmbi->e2m, ASPEED_E2M_EVENT_EN, &value); -+ value |= BIT(mmbi->e2m_h2b_int); -+ regmap_write(mmbi->e2m, ASPEED_E2M_EVENT_EN, value); -+ -+ /* B2H Write Protect */ -+ sprot_size = (mmbi->mem_size / 2) / SZ_1M; -+ value = (sprot_size << 16) | (mmbi->mem_phy >> 20); -+ regmap_write(mmbi->e2m, ASPEED_E2M_SPROT_ADR0 + (4 * e2m_index), value); -+ /* Enable read & disalbe write */ -+ value = 1 << (8 + e2m_index); -+ regmap_write(mmbi->e2m, ASPEED_E2M_SPROT_CTL0 + (4 * e2m_index), value); -+ /* Set PID */ -+ regmap_read(mmbi->e2m, ASPEED_E2M_SPROT_SIDG0 + (4 * (e2m_index / 4)), &value); -+ value |= pid << (8 * (e2m_index % 4)); -+ regmap_write(mmbi->e2m, ASPEED_E2M_SPROT_SIDG0 + (4 * (e2m_index / 4)), value); -+ -+ mmbi->chan.dev = dev; -+ mmbi->chan.mmbi = mmbi; -+ ret = aspeed_pcie_mmbi_init(mmbi); -+ if (ret < 0) { -+ dev_err(dev, "Initialize MMBI device failed.\n"); -+ return ret; -+ } ++static void aspeed_usb_hp_remove(struct platform_device *pdev) ++{ ++ dev_info(&pdev->dev, "Remove USB Host PCIe\n"); ++} + -+ INIT_WORK(&chan->work, aspeed_mmbi_work_func); ++static struct platform_driver aspeed_usb_hp_driver = { ++ .probe = aspeed_usb_hp_probe, ++ .remove = aspeed_usb_hp_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_usb_hp_dt_ids, ++ }, ++}; ++module_platform_driver(aspeed_usb_hp_driver); + -+ return 0; -+} ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Neal Liu "); +diff --git a/drivers/soc/aspeed/aspeed-usb-phy.c b/drivers/soc/aspeed/aspeed-usb-phy.c +--- a/drivers/soc/aspeed/aspeed-usb-phy.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-usb-phy.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,112 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2021 Aspeed Technology Inc. ++ */ + -+struct aspeed_platform ast2700_platform = { -+ .mmbi_init = aspeed_ast2700_pcie_mmbi_init, ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct usb_phy_ctrl { ++ u32 offset; ++ u32 value; +}; + -+static const struct of_device_id aspeed_pcie_mmbi_of_matches[] = { -+ { .compatible = "aspeed,ast2700-pcie-mmbi", .data = &ast2700_platform }, -+ {}, ++static const struct of_device_id aspeed_usb_phy_dt_ids[] = { ++ { ++ .compatible = "aspeed,ast2600-uphyb", ++ }, ++ { ++ .compatible = "aspeed,ast2700-uphy2a", ++ }, ++ { ++ .compatible = "aspeed,ast2700-uphy2b", ++ }, ++ { } +}; -+MODULE_DEVICE_TABLE(of, aspeed_pcie_mmbi_of_matches); ++MODULE_DEVICE_TABLE(of, aspeed_usb_phy_dt_ids); + -+static int aspeed_pcie_mmbi_probe(struct platform_device *pdev) ++static int aspeed_usb_phy_probe(struct platform_device *pdev) +{ -+ struct aspeed_pcie_mmbi *mmbi; -+ struct aspeed_mmbi_channel *chan; -+ struct device *dev = &pdev->dev; -+ struct resource res; -+ struct device_node *np; -+ const void *md; -+ int ret = 0; ++ struct device_node *node = pdev->dev.of_node; ++ struct usb_phy_ctrl *ctrl_data; ++ void __iomem *base; ++ struct regmap *scu; ++ int ctrl_num = 1; ++ int ret, i; ++ u32 val; + -+ md = of_device_get_match_data(dev); -+ if (!md) ++ scu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "aspeed,scu"); ++ if (IS_ERR(scu)) { ++ dev_err(&pdev->dev, "cannot to find SCU regmap\n"); + return -ENODEV; -+ -+ mmbi = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_pcie_mmbi), GFP_KERNEL); -+ if (!mmbi) -+ return -ENOMEM; -+ dev_set_drvdata(dev, mmbi); -+ -+ mmbi->dev = dev; -+ mmbi->platform = md; -+ -+ /* Get MMBI memory size */ -+ np = of_parse_phandle(dev->of_node, "memory-region", 0); -+ if (!np || of_address_to_resource(np, 0, &res)) { -+ dev_err(dev, "Failed to find memory-region.\n"); -+ ret = -ENOMEM; -+ goto out_region; + } + -+ of_node_put(np); -+ -+ mmbi->mem_phy = res.start; -+ mmbi->mem_size = resource_size(&res); -+ mmbi->mem_virt = ioremap(mmbi->mem_phy, mmbi->mem_size); -+ if (!mmbi->mem_virt) { -+ dev_err(dev, "cannot map mmbi memory region\n"); -+ ret = -ENOMEM; -+ goto out_region; ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2600-uphyb")) { ++ /* Check SCU040[3] USB port B controller reset is deassert */ ++ regmap_read(scu, 0x40, &val); ++ if ((val & BIT(3))) ++ return -EPROBE_DEFER; + } + -+ /* Get IRQ */ -+ mmbi->irq = platform_get_irq(pdev, 0); -+ if (mmbi->irq < 0) { -+ dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", mmbi->irq); -+ goto out_unmap; ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2700-uphy2a")) { ++ /* Check SCU220[0] USB vHubA1 controller reset is deassert */ ++ regmap_read(scu, 0x220, &val); ++ if ((val & BIT(0))) ++ return -EPROBE_DEFER; + } -+ ret = devm_request_irq(&pdev->dev, mmbi->irq, aspeed_pcie_mmbi_isr, 0, dev_name(&pdev->dev), -+ mmbi); -+ if (ret) { -+ dev_err(dev, "pcie mmbi unable to get IRQ"); -+ goto out_unmap; ++ ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2700-uphy2b")) { ++ /* Check SCU220[3] USB vHubB1 controller reset is deassert */ ++ regmap_read(scu, 0x220, &val); ++ if ((val & BIT(3))) ++ return -EPROBE_DEFER; + } + -+ chan = &mmbi->chan; -+ memset(chan, 0, sizeof(struct aspeed_mmbi_channel)); ++ ctrl_data = devm_kzalloc(&pdev->dev, ++ sizeof(struct usb_phy_ctrl) * ctrl_num, ++ GFP_KERNEL); ++ if (!ctrl_data) ++ return -ENOMEM; + -+ chan->bmc_int_en = true; -+ /* H2B Interrupt */ -+ ret = of_property_read_u8(dev->of_node, "bmc-int-value", &chan->bmc_int_value); -+ if (ret) { -+ dev_err(dev, "cannot get valid MMBI H2B interrupt value\n"); -+ chan->bmc_int_en = false; -+ } -+ ret = of_property_read_u32(dev->of_node, "bmc-int-location", &chan->bmc_int_location); -+ if (ret) { -+ dev_err(dev, "cannot get valid MMBI H2B interrupt location\n"); -+ chan->bmc_int_en = false; -+ } -+ /* B2H Interrupt */ -+ chan->host_int_en = true; -+ ret = of_property_read_u8(dev->of_node, "msi", &chan->host_int_value); -+ if (ret) { -+ dev_err(dev, "cannot get valid MMBI B2H interrupt location\n"); -+ chan->host_int_en = false; -+ } ++ base = of_iomap(node, 0); + -+ ret = mmbi->platform->mmbi_init(pdev); -+ if (ret) { -+ dev_err(dev, "Initialize pcie mmbi failed\n"); -+ goto out_irq; ++ ret = of_property_read_u32_array(node, "ctrl", (u32 *)ctrl_data, ++ ctrl_num * 2); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Could not read ctrl property\n"); ++ return -EINVAL; + } + -+ dev_info(dev, "ASPEED PCIe MMBI Dev %d: driver successfully loaded.\n", mmbi->id); ++ for (i = 0; i < ctrl_num; i++) ++ writel(ctrl_data[i].value, base + ctrl_data[i].offset); ++ ++ dev_info(&pdev->dev, "Initialized USB PHY\n"); + + return 0; -+out_irq: -+ devm_free_irq(dev, mmbi->irq, mmbi); -+out_unmap: -+ iounmap(mmbi->mem_virt); -+out_region: -+ devm_kfree(dev, mmbi); -+ dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret); -+ return ret; +} + -+static void aspeed_pcie_mmbi_remove(struct platform_device *pdev) ++static void aspeed_usb_phy_remove(struct platform_device *pdev) +{ -+ struct aspeed_pcie_mmbi *mmbi = platform_get_drvdata(pdev); -+ -+ cancel_work_sync(&mmbi->chan.work); -+ unregister_netdev(mmbi->chan.ndev); -+ devm_free_irq(&pdev->dev, mmbi->irq, mmbi); -+ iounmap(mmbi->mem_virt); -+ devm_kfree(&pdev->dev, mmbi); +} + -+static struct platform_driver aspeed_pcie_mmbi_driver = { -+ .probe = aspeed_pcie_mmbi_probe, -+ .remove = aspeed_pcie_mmbi_remove, ++static struct platform_driver aspeed_usb_phy_driver = { ++ .probe = aspeed_usb_phy_probe, ++ .remove = aspeed_usb_phy_remove, + .driver = { + .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_pcie_mmbi_of_matches, ++ .of_match_table = aspeed_usb_phy_dt_ids, + }, +}; ++module_platform_driver(aspeed_usb_phy_driver); + -+module_platform_driver(aspeed_pcie_mmbi_driver); -+ -+MODULE_AUTHOR("Jacky Chou "); -+MODULE_DESCRIPTION("ASPEED PCI-E MMBI Driver"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/aspeed-pcie-mmbi.h b/drivers/soc/aspeed/aspeed-pcie-mmbi.h ---- a/drivers/soc/aspeed/aspeed-pcie-mmbi.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-pcie-mmbi.h 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,141 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright 2024 Aspeed Technology Inc. -+ */ -+#ifndef __ASPEED_PCIE_MMBI_H__ -+#define __ASPEED_PCIE_MMBI_H__ ++MODULE_AUTHOR("Neal Liu "); +diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c +--- a/drivers/soc/aspeed/aspeed-xdma.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/aspeed-xdma.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,1379 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright IBM Corp 2019 + -+#define MMBI_SIGNATURE "#MMBI$" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVICE_NAME "aspeed-xdma" ++ ++#define SCU_AST2600_MISC_CTRL 0x0c0 ++#define SCU_AST2600_MISC_CTRL_XDMA_BMC BIT(8) ++#define SCU_AST2700_MISC_CTRL_XDMA_CLIENT BIT(4) ++ ++#define SCU_AST2600_DEBUG_CTRL 0x0c8 ++#define DEBUG_CTRL_AST2600_XDMA_DISABLE BIT(2) ++#define DEBUG_CTRL_AST2700_XDMA_DISABLE BIT(8) ++ ++#define SCU_AST2500_PCIE_CONF 0x180 ++#define SCU_AST2600_PCIE_CONF 0xc20 ++#define SCU_AST2700_PCIE0_CONF 0x970 ++#define SCU_AST2700_PCIE1_CONF 0x9B0 ++#define SCU_PCIE_CONF_VGA_EN BIT(0) ++#define SCU_PCIE_CONF_VGA_EN_MMIO BIT(1) ++#define SCU_PCIE_CONF_VGA_EN_LPC BIT(2) ++#define SCU_PCIE_CONF_VGA_EN_MSI BIT(3) ++#define SCU_PCIE_CONF_VGA_EN_MCTP BIT(4) ++#define SCU_PCIE_CONF_VGA_EN_IRQ BIT(5) ++#define SCU_PCIE_CONF_VGA_EN_DMA BIT(6) ++#define SCU_PCIE_CONF_BMC_EN BIT(8) ++#define SCU_PCIE_CONF_BMC_EN_MMIO BIT(9) ++#define SCU_PCIE_CONF_BMC_EN_MSI BIT(11) ++#define SCU_PCIE_CONF_BMC_EN_MCTP BIT(12) ++#define SCU_PCIE_CONF_BMC_EN_IRQ BIT(13) ++#define SCU_PCIE_CONF_BMC_EN_DMA BIT(14) ++ ++#define SCU_AST2700_PCIE0_CTRL 0xa60 ++#define SCU_AST2700_PCIE1_CTRL 0xae0 ++#define SCU_AST2700_PCIE_CTRL_DMA_EN BIT(2) ++ ++#define SCU_AST2500_BMC_CLASS_REV 0x19c ++#define SCU_AST2600_BMC_CLASS_REV 0xc68 ++#define SCU_AST2700_PCIE0_BMC_CLASS_REV 0xa18 ++#define SCU_AST2700_PCIE1_BMC_CLASS_REV 0xa98 ++#define SCU_BMC_CLASS_REV_XDMA 0xff000001 ++#define SCU_BMC_CLASS_REV_MASK 0xffffff00 ++ ++#define XDMA_CMDQ_SIZE PAGE_SIZE ++#define XDMA_NUM_CMDS \ ++ (XDMA_CMDQ_SIZE / sizeof(struct aspeed_xdma_cmd)) ++ ++/* Aspeed specification requires 100us after disabling the reset */ ++#define XDMA_ENGINE_SETUP_TIME_MAX_US 1000 ++#define XDMA_ENGINE_SETUP_TIME_MIN_US 100 ++ ++#define XDMA_CMD_AST2500_PITCH_SHIFT 3 ++#define XDMA_CMD_AST2500_PITCH_BMC GENMASK_ULL(62, 51) ++#define XDMA_CMD_AST2500_PITCH_HOST GENMASK_ULL(46, 35) ++#define XDMA_CMD_AST2500_PITCH_UPSTREAM BIT_ULL(31) ++#define XDMA_CMD_AST2500_PITCH_ADDR GENMASK_ULL(29, 4) ++#define XDMA_CMD_AST2500_PITCH_ID BIT_ULL(0) ++#define XDMA_CMD_AST2500_CMD_IRQ_EN BIT_ULL(31) ++#define XDMA_CMD_AST2500_CMD_LINE_NO GENMASK_ULL(27, 16) ++#define XDMA_CMD_AST2500_CMD_IRQ_BMC BIT_ULL(15) ++#define XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT 4 ++#define XDMA_CMD_AST2500_CMD_LINE_SIZE \ ++ GENMASK_ULL(14, XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT) ++#define XDMA_CMD_AST2500_CMD_ID BIT_ULL(1) + -+//This definitions are as per MMBI specification. -+#define MMBI_PROTOCOL_IPMI 1 -+#define MMBI_PROTOCOL_SEAMLESS 2 -+#define MMBI_PROTOCOL_RAS_OFFLOAD 3 -+#define MMBI_PROTOCOL_MCTP 4 -+#define MMBI_PROTOCOL_NODE_MANAGER 5 ++#define XDMA_CMD_AST2600_PITCH_BMC GENMASK_ULL(62, 48) ++#define XDMA_CMD_AST2600_PITCH_HOST GENMASK_ULL(46, 32) ++#define XDMA_CMD_AST2600_PITCH_ADDR GENMASK_ULL(30, 0) ++#define XDMA_CMD_AST2600_CMD_64_EN BIT_ULL(40) ++#define XDMA_CMD_AST2600_CMD_IRQ_BMC BIT_ULL(37) ++#define XDMA_CMD_AST2600_CMD_IRQ_HOST BIT_ULL(36) ++#define XDMA_CMD_AST2600_CMD_UPSTREAM BIT_ULL(32) ++#define XDMA_CMD_AST2600_CMD_LINE_NO GENMASK_ULL(27, 16) ++#define XDMA_CMD_AST2600_CMD_LINE_SIZE GENMASK_ULL(14, 0) ++#define XDMA_CMD_AST2600_CMD_MULTILINE_SIZE GENMASK_ULL(14, 12) + -+#define MMBI_HRWS0(x) readl((x)->hrws_vmem) -+#define MMBI_HRWS1(x) readl((x)->hrws_vmem + 4) -+#define MMBI_HROS0(x) readl((x)->hros_vmem) -+#define MMBI_HROS1(x) readl((x)->hros_vmem + 4) ++#define XDMA_CMD_AST2700_PITCH_BMC GENMASK_ULL(62, 48) ++#define XDMA_CMD_AST2700_PITCH_HOST GENMASK_ULL(46, 32) ++#define XDMA_CMD_AST2700_CMD_64_EN BIT_ULL(40) ++#define XDMA_CMD_AST2700_CMD_IRQ_BMC BIT_ULL(37) ++#define XDMA_CMD_AST2700_CMD_UPSTREAM BIT_ULL(32) ++#define XDMA_CMD_AST2700_CMD_LINE_NO GENMASK_ULL(27, 16) ++#define XDMA_CMD_AST2700_CMD_LINE_SIZE GENMASK_ULL(14, 0) ++#define XDMA_CMD_AST2700_CMD_MULTILINE_SIZE GENMASK_ULL(14, 12) ++#define XDMA_CMD_AST2700_BMC_ADDR GENMASK_ULL(34, 0) + -+#define H2B_WRITE_POINTER_MASK GENMASK(31, 2) -+#define H2B_READ_POINTER_MASK GENMASK(31, 2) -+#define B2H_WRITE_POINTER_MASK GENMASK(31, 2) -+#define B2H_READ_POINTER_MASK GENMASK(31, 2) ++#define XDMA_AST2500_QUEUE_ENTRY_SIZE 4 ++#define XDMA_AST2500_HOST_CMDQ_ADDR0 0x00 ++#define XDMA_AST2500_HOST_CMDQ_ENDP 0x04 ++#define XDMA_AST2500_HOST_CMDQ_WRITEP 0x08 ++#define XDMA_AST2500_HOST_CMDQ_READP 0x0c ++#define XDMA_AST2500_BMC_CMDQ_ADDR 0x10 ++#define XDMA_AST2500_BMC_CMDQ_ENDP 0x14 ++#define XDMA_AST2500_BMC_CMDQ_WRITEP 0x18 ++#define XDMA_AST2500_BMC_CMDQ_READP 0x1c ++#define XDMA_BMC_CMDQ_READP_RESET 0xee882266 ++#define XDMA_AST2500_CTRL 0x20 ++#define XDMA_AST2500_CTRL_US_COMP BIT(4) ++#define XDMA_AST2500_CTRL_DS_COMP BIT(5) ++#define XDMA_AST2500_CTRL_DS_DIRTY BIT(6) ++#define XDMA_AST2500_CTRL_DS_SIZE_256 BIT(17) ++#define XDMA_AST2500_CTRL_DS_TIMEOUT BIT(28) ++#define XDMA_AST2500_CTRL_DS_CHECK_ID BIT(29) ++#define XDMA_AST2500_STATUS 0x24 ++#define XDMA_AST2500_STATUS_US_COMP BIT(4) ++#define XDMA_AST2500_STATUS_DS_COMP BIT(5) ++#define XDMA_AST2500_STATUS_DS_DIRTY BIT(6) ++#define XDMA_AST2500_INPRG_DS_CMD1 0x38 ++#define XDMA_AST2500_INPRG_DS_CMD2 0x3c ++#define XDMA_AST2500_INPRG_US_CMD00 0x40 ++#define XDMA_AST2500_INPRG_US_CMD01 0x44 ++#define XDMA_AST2500_INPRG_US_CMD10 0x48 ++#define XDMA_AST2500_INPRG_US_CMD11 0x4c ++#define XDMA_AST2500_INPRG_US_CMD20 0x50 ++#define XDMA_AST2500_INPRG_US_CMD21 0x54 ++#define XDMA_AST2500_HOST_CMDQ_ADDR1 0x60 ++#define XDMA_AST2500_VGA_CMDQ_ADDR0 0x64 ++#define XDMA_AST2500_VGA_CMDQ_ENDP 0x68 ++#define XDMA_AST2500_VGA_CMDQ_WRITEP 0x6c ++#define XDMA_AST2500_VGA_CMDQ_READP 0x70 ++#define XDMA_AST2500_VGA_CMD_STATUS 0x74 ++#define XDMA_AST2500_VGA_CMDQ_ADDR1 0x78 + -+#define GET_H2B_WRITE_POINTER(x) (MMBI_HRWS0(x) & H2B_WRITE_POINTER_MASK) -+#define GET_H2B_READ_POINTER(x) (MMBI_HROS1(x) & H2B_READ_POINTER_MASK) -+#define GET_B2H_WRITE_POINTER(x) (MMBI_HROS0(x) & B2H_WRITE_POINTER_MASK) -+#define GET_B2H_READ_POINTER(x) (MMBI_HRWS1(x) & B2H_READ_POINTER_MASK) ++#define XDMA_AST2600_QUEUE_ENTRY_SIZE 2 ++#define XDMA_AST2600_HOST_CMDQ_ADDR0 0x00 ++#define XDMA_AST2600_HOST_CMDQ_ADDR1 0x04 ++#define XDMA_AST2600_HOST_CMDQ_ENDP 0x08 ++#define XDMA_AST2600_HOST_CMDQ_WRITEP 0x0c ++#define XDMA_AST2600_HOST_CMDQ_READP 0x10 ++#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14 ++#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18 ++#define XDMA_AST2600_BMC_CMDQ_WRITEP 0x1c ++#define XDMA_AST2600_BMC_CMDQ_READP 0x20 ++#define XDMA_AST2600_VGA_CMDQ_ADDR0 0x24 ++#define XDMA_AST2600_VGA_CMDQ_ADDR1 0x28 ++#define XDMA_AST2600_VGA_CMDQ_ENDP 0x2c ++#define XDMA_AST2600_VGA_CMDQ_WRITEP 0x30 ++#define XDMA_AST2600_VGA_CMDQ_READP 0x34 ++#define XDMA_AST2600_CTRL 0x38 ++#define XDMA_AST2600_CTRL_US_COMP BIT(16) ++#define XDMA_AST2600_CTRL_DS_COMP BIT(17) ++#define XDMA_AST2600_CTRL_DS_DIRTY BIT(18) ++#define XDMA_AST2600_CTRL_DS_SIZE_256 BIT(20) ++#define XDMA_AST2600_STATUS 0x3c ++#define XDMA_AST2600_STATUS_US_COMP BIT(16) ++#define XDMA_AST2600_STATUS_DS_COMP BIT(17) ++#define XDMA_AST2600_STATUS_DS_DIRTY BIT(18) ++#define XDMA_AST2600_INPRG_DS_CMD00 0x40 ++#define XDMA_AST2600_INPRG_DS_CMD01 0x44 ++#define XDMA_AST2600_INPRG_DS_CMD10 0x48 ++#define XDMA_AST2600_INPRG_DS_CMD11 0x4c ++#define XDMA_AST2600_INPRG_DS_CMD20 0x50 ++#define XDMA_AST2600_INPRG_DS_CMD21 0x54 ++#define XDMA_AST2600_INPRG_US_CMD00 0x60 ++#define XDMA_AST2600_INPRG_US_CMD01 0x64 ++#define XDMA_AST2600_INPRG_US_CMD10 0x68 ++#define XDMA_AST2600_INPRG_US_CMD11 0x6c ++#define XDMA_AST2600_INPRG_US_CMD20 0x70 ++#define XDMA_AST2600_INPRG_US_CMD21 0x74 + -+#define GET_HOST_READY_BIT(x) (MMBI_HRWS1(x) & 0x01) -+#define GET_BMC_READY_BIT(x) (MMBI_HROS1(x) & 0x01) ++#define XDMA_AST2700_QUEUE_ENTRY_SIZE 2 ++#define XDMA_AST2700_BMC_CMDQ_ADDR0 0x10 ++#define XDMA_AST2700_BMC_CMDQ_ADDR1 0x14 ++#define XDMA_AST2700_BMC_CMDQ_ENDP 0x18 ++#define XDMA_AST2700_BMC_CMDQ_WRITEP 0x1c ++#define XDMA_AST2700_BMC_CMDQ_READP 0x20 ++#define XDMA_AST2700_CTRL 0x38 ++#define XDMA_AST2700_CTRL_US_COMP BIT(16) ++#define XDMA_AST2700_CTRL_DS_COMP BIT(17) ++#define XDMA_AST2700_CTRL_DS_DIRTY BIT(18) ++#define XDMA_AST2700_CTRL_IDLE BIT(19) ++#define XDMA_AST2700_CTRL_DS_SIZE_256 BIT(20) ++#define XDMA_AST2700_STATUS 0x3c ++#define XDMA_AST2700_STATUS_US_COMP BIT(16) ++#define XDMA_AST2700_STATUS_DS_COMP BIT(17) ++#define XDMA_AST2700_STATUS_DS_DIRTY BIT(18) ++#define XDMA_AST2700_STATUS_IDLE BIT(19) ++#define XDMA_AST2700_INPRG_DS_CMD00 0x40 ++#define XDMA_AST2700_INPRG_DS_CMD01 0x44 ++#define XDMA_AST2700_INPRG_DS_CMD10 0x48 ++#define XDMA_AST2700_INPRG_DS_CMD11 0x4c ++#define XDMA_AST2700_INPRG_DS_CMD20 0x50 ++#define XDMA_AST2700_INPRG_DS_CMD21 0x54 ++#define XDMA_AST2700_INPRG_US_CMD00 0x60 ++#define XDMA_AST2700_INPRG_US_CMD01 0x64 ++#define XDMA_AST2700_INPRG_US_CMD10 0x68 ++#define XDMA_AST2700_INPRG_US_CMD11 0x6c ++#define XDMA_AST2700_INPRG_US_CMD20 0x70 ++#define XDMA_AST2700_INPRG_US_CMD21 0x74 + -+typedef u8 protocol_type; ++struct aspeed_xdma_cmd { ++ u64 host_addr; ++ u64 pitch; ++ u64 cmd; ++ u64 reserved; ++}; + -+enum mmbi_state { /* B_U B_R H_U H_R */ -+ INIT_IN_PROGRESS = 0x00, /* 0 0 0 0 */ -+ INIT_COMPLETED = 0x08, /* 1 0 0 0 */ -+ NORMAL_RUNTIME = 0x0A, /* 1 0 1 0 */ -+ RESET_REQ_BY_BMC = 0x0E, /* 1 1 1 0 */ -+ RESET_REQ_BY_HOST = 0x0B, /* 1 0 1 1 */ -+ RESET_ACKED = 0x0F, /* 1 1 1 1 */ -+ TRANS_TO_INIT = 0x07, /* 0 1 1 1 */ -+ INIT_MISMATCH = 0x09, /* 1 0 0 1 */ -+ POWER_UP_OR_ERROR = 0x80000000, ++struct aspeed_xdma_regs { ++ u8 bmc_cmdq_addr; ++ u8 bmc_cmdq_addr_ext; ++ u8 bmc_cmdq_endp; ++ u8 bmc_cmdq_writep; ++ u8 bmc_cmdq_readp; ++ u8 control; ++ u8 status; +}; + -+struct mmbi_header { -+ u32 pkt_pad : 2; -+ u32 pkt_len : 22; -+ u32 pkt_type : 4; -+ u32 reserved : 4; -+}; -+ -+struct host_ros { -+ u32 b_rst : 1; /* BMC Reset Request */ -+ u32 b_up : 1; /* BMC Interface Up */ -+ u32 b2h_wp : 30; /* B2H Write Pointer */ -+ u32 b_rdy : 1; /* BMC Ready */ -+ u32 reserved1 : 1; -+ u32 h2b_rp : 30; /* H2B Read Pointer */ -+}; -+ -+struct host_rws { -+ u32 h_rst : 1; /* Host Reset Request */ -+ u32 h_up : 1; /* Host Interface Up */ -+ u32 h2b_wp : 30; /* H2B Write Pointer */ -+ u32 h_rdy : 1; /* Host Ready */ -+ u32 reserved1 : 1; -+ u32 b2h_rp : 30; /* B2H Read Pointer */ -+}; -+ -+struct buffer_type_desc { -+ u32 h_ros_p; /* Host Read-Only Structure Pointer */ -+ u32 h_rws_p; /* Host Read-Write Structure Pointer */ -+ u8 h_int_t; /* Host Interrupt Type */ -+ u8 h_int_l; /* Host Interrupt Location */ -+ u8 reserved1[3]; -+ u8 h_int_v; /* Host Interrupt Value */ -+ u8 bmc_int_t; /* BMC Interrupt Type */ -+ u32 bmc_int_l; /* BMC Interrupt Location */ -+ u8 reserved2[4]; -+ u8 bmc_int_v; /* BMC Interrupt Value */ -+} __packed; ++struct aspeed_xdma_status_bits { ++ u32 us_comp; ++ u32 ds_comp; ++ u32 ds_dirty; ++}; + -+struct mmbi_cap_desc { -+ u8 signature[6]; -+ u8 version; -+ u8 os_use; -+ u32 b2h_ba; /* B2H Buffer Base Address */ -+ u32 h2b_ba; /* H2B Buffer Base Address */ -+ u32 b2h_l; /* B2H Buffer Length */ -+ u32 h2b_l; /* H2B Buffer Length */ -+ u8 buffer_type; -+ u8 reserved1[7]; -+ struct buffer_type_desc bt_desc; -+ u8 reserved2[8]; -+} __packed; ++struct aspeed_xdma; + -+struct aspeed_pcie_mmbi; ++struct aspeed_xdma_chip { ++ u32 control; ++ u32 scu_bmc_class; ++ u32 scu_misc_ctrl; ++ u32 scu_misc_mask; ++ u32 scu_disable_mask; ++ u32 scu_pcie_conf; ++ u32 scu_pcie_ctrl; ++ unsigned int queue_entry_size; ++ struct aspeed_xdma_regs regs; ++ struct aspeed_xdma_status_bits status_bits; ++ unsigned int (*set_cmd)(struct aspeed_xdma *ctx, ++ struct aspeed_xdma_cmd cmds[2], ++ struct aspeed_xdma_op *op, u64 bmc_addr); ++}; + -+#define MCTP_MMBI_MTU 65536 -+#define MCTP_MMBI_MTU_MIN 68 /* base mtu (64) + mctp header */ -+#define MCTP_MMBI_MTU_MAX 65536 ++struct aspeed_xdma_client; + -+struct aspeed_mmbi_mctp { -+ struct aspeed_pcie_mmbi *mmbi; -+ struct net_device *ndev; -+}; ++struct aspeed_xdma { ++ struct kobject kobj; ++ const struct aspeed_xdma_chip *chip; + -+struct aspeed_mmbi_channel { -+ struct aspeed_pcie_mmbi *mmbi; ++ int irq; ++ int pcie_irq; ++ struct clk *clock; + struct device *dev; ++ void __iomem *base; ++ struct reset_control *reset; ++ struct reset_control *reset_rc; + -+ u32 b2h_cb_size; -+ u32 h2b_cb_size; -+ u8 __iomem *desc_vmem; -+ u8 __iomem *hros_vmem; -+ u8 __iomem *b2h_cb_vmem; -+ u8 __iomem *hrws_vmem; -+ u8 __iomem *h2b_cb_vmem; ++ /* Protects current_client */ ++ spinlock_t client_lock; ++ struct aspeed_xdma_client *current_client; + -+ bool bmc_int_en; -+ u8 bmc_int_value; -+ u32 bmc_int_location; -+ u8 __iomem *bmc_int_vmem; ++ /* Protects engine configuration */ ++ spinlock_t engine_lock; ++ struct aspeed_xdma_cmd *cmdq; ++ unsigned int cmd_idx; ++ bool in_reset; ++ bool upstream; + -+ bool host_int_en; -+ u8 host_int_location; -+ u8 host_int_value; ++ /* Queue waiters for idle engine */ ++ wait_queue_head_t wait; + -+ enum mmbi_state state; ++ struct work_struct reset_work; + -+ /* MCTP */ -+ struct net_device *ndev; ++ phys_addr_t mem_phys; ++ phys_addr_t mem_size; ++ void *mem_virt; ++ dma_addr_t mem_coherent; ++ dma_addr_t cmdq_phys; ++ struct gen_pool *pool; + -+ struct work_struct work; ++ struct miscdevice misc; +}; + -+#endif -diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c ---- a/drivers/soc/aspeed/aspeed-socinfo.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-socinfo.c 2025-12-23 10:16:21.125032653 +0000 -@@ -27,6 +27,10 @@ - { "AST2620", 0x05010203 }, - { "AST2605", 0x05030103 }, - { "AST2625", 0x05030403 }, -+ /* AST2700 */ -+ { "AST2750", 0x06000003 }, -+ { "AST2700", 0x06000103 }, -+ { "AST2720", 0x06000203 }, - }; - - static const char *siliconid_to_name(u32 siliconid) -diff --git a/drivers/soc/aspeed/aspeed-ssp.c b/drivers/soc/aspeed/aspeed-ssp.c ---- a/drivers/soc/aspeed/aspeed-ssp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-ssp.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,275 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright (C) ASPEED Technology Inc. -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SSP_FILE_NAME "ast2600_ssp.bin" -+#define AST2600_CVIC_TRIGGER 0x28 -+#define AST2600_CVIC_PENDING_STATUS 0x18 -+#define AST2600_CVIC_PENDING_CLEAR 0x1C -+ -+#define SSP_CTRL_REG 0xa00 -+#define SSP_CTRL_RESET_ASSERT BIT(1) -+#define SSP_CTRL_EN BIT(0) -+ -+#define SSP_MEM_BASE_REG 0xa04 -+#define SSP_IMEM_LIMIT_REG 0xa08 -+#define SSP_DMEM_LIMIT_REG 0xa0c -+#define SSP_CACHE_RANGE_REG 0xa40 -+#define SSP_CACHE_INVALID_REG 0xa44 -+#define SSP_CACHE_CTRL_REG 0xa48 -+#define SSP_CACHE_CLEAR_ICACHE BIT(2) -+#define SSP_CACHE_CLEAR_DCACHE BIT(1) -+#define SSP_CACHE_EN BIT(0) -+ -+#define SSP_TOTAL_MEM_SZ (32 * 1024 * 1024) -+#define SSP_CACHED_MEM_SZ (16 * 1024 * 1024) -+#define SSP_UNCACHED_MEM_SZ (SSP_TOTAL_MEM_SZ - SSP_CACHED_MEM_SZ) -+#define SSP_CACHE_1ST_16MB_ENABLE BIT(0) ++struct aspeed_xdma_client { ++ struct aspeed_xdma *ctx; + -+struct ast2600_ssp { -+ struct device *dev; -+ struct regmap *scu; -+ dma_addr_t ssp_mem_phy_addr; -+ void __iomem *ssp_mem_vir_addr; -+ dma_addr_t ssp_shared_mem_phy_addr; -+ void __iomem *ssp_shared_mem_vir_addr; -+ int ssp_shared_mem_size; -+ void __iomem *cvic; -+ int irq[16]; -+ int n_irq; ++ bool error; ++ bool in_progress; ++ void *virt; ++ dma_addr_t phys; ++ u32 size; +}; + -+static int ast_ssp_open(struct inode *inode, struct file *file) ++#define CREATE_TRACE_POINTS ++#include ++ ++static u32 aspeed_xdma_readl(struct aspeed_xdma *ctx, u8 reg) +{ -+ return 0; ++ u32 v = readl(ctx->base + reg); ++ ++ dev_dbg(ctx->dev, "read %02x[%08x]\n", reg, v); ++ return v; +} + -+static int ast_ssp_release(struct inode *inode, struct file *file) ++static void aspeed_xdma_writel(struct aspeed_xdma *ctx, u8 reg, u32 val) +{ -+ return 0; ++ writel(val, ctx->base + reg); ++ dev_dbg(ctx->dev, "write %02x[%08x]\n", reg, val); +} + -+static const struct file_operations ast_ssp_fops = { -+ .owner = THIS_MODULE, -+ .open = ast_ssp_open, -+ .release = ast_ssp_release, -+ .llseek = noop_llseek, -+}; -+ -+struct miscdevice ast_ssp_misc = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "ast-ssp", -+ .fops = &ast_ssp_fops, -+}; -+ -+static irqreturn_t ast2600_ssp_interrupt(int irq, void *dev_id) ++static void aspeed_xdma_init_eng(struct aspeed_xdma *ctx) +{ -+ u32 i; -+ struct ast2600_ssp *priv = dev_id; -+ u32 isr = readl(priv->cvic + AST2600_CVIC_PENDING_STATUS); -+ u32 ssp_shared_rx_tx_size = priv->ssp_shared_mem_size / 2; -+ u32 *ssp_shared_mem_tx = priv->ssp_shared_mem_vir_addr; -+ u32 *ssp_shared_mem_rx = priv->ssp_shared_mem_vir_addr + ssp_shared_rx_tx_size; -+ -+ dev_info(priv->dev, "isr %x\n", isr); -+ writel(isr, priv->cvic + AST2600_CVIC_PENDING_CLEAR); -+ -+ dev_info(priv->dev, "[CA7] rx addr:%08x, tx addr:%08x\n", -+ (u32)ssp_shared_mem_rx, (u32)ssp_shared_mem_tx); ++ unsigned long flags; + -+ /* Check the CA7 RX data from CM3 TX data. */ -+ dev_info(priv->dev, "CA7 RX data from CM3 TX data: "); -+ for (i = 0; i < ssp_shared_rx_tx_size / 4; i++) { -+ if (readl(ssp_shared_mem_rx + i) != 0) { -+ dev_info(priv->dev, "[%08x] %08x ", -+ (u32)(ssp_shared_mem_rx + i), readl(ssp_shared_mem_rx + i)); -+ } else { -+ break; -+ } -+ } ++ spin_lock_irqsave(&ctx->engine_lock, flags); ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_endp, ++ ctx->chip->queue_entry_size * XDMA_NUM_CMDS); ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_readp, ++ XDMA_BMC_CMDQ_READP_RESET); ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, 0); ++ aspeed_xdma_writel(ctx, ctx->chip->regs.control, ctx->chip->control); ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_addr, ctx->cmdq_phys); ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ if (ctx->chip->regs.bmc_cmdq_addr_ext) ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_addr_ext, ctx->cmdq_phys >> 32); ++#endif + -+ return IRQ_HANDLED; ++ ctx->cmd_idx = 0; ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); +} + -+static int ast_ssp_probe(struct platform_device *pdev) ++static unsigned int aspeed_xdma_ast2500_set_cmd(struct aspeed_xdma *ctx, ++ struct aspeed_xdma_cmd cmds[2], ++ struct aspeed_xdma_op *op, ++ u64 bmc_addr) +{ -+ struct device_node *np, *mnode = dev_of_node(&pdev->dev); -+ const struct firmware *firmware; -+ struct ast2600_ssp *priv; -+ struct reserved_mem *rmem; -+ int i, ret; -+ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) { -+ ret = -ENOMEM; -+ goto finish; -+ } -+ -+ priv->dev = &pdev->dev; -+ priv->scu = syscon_regmap_lookup_by_phandle(priv->dev->of_node, "aspeed,scu"); -+ if (IS_ERR(priv->scu)) { -+ dev_err(priv->dev, "failed to find SCU regmap\n"); -+ ret = -EINVAL; -+ goto finish; -+ } -+ platform_set_drvdata(pdev, priv); -+ -+ ret = misc_register(&ast_ssp_misc); -+ if (ret) { -+ pr_err("can't misc_register :(\n"); -+ ret = -EIO; -+ goto finish; -+ } -+ dev_set_drvdata(ast_ssp_misc.this_device, pdev); -+ -+ ret = of_reserved_mem_device_init(&pdev->dev); -+ if (ret) { -+ dev_err(priv->dev, -+ "failed to initialize reserved mem: %d\n", ret); -+ ret = -ENOMEM; -+ goto finish; -+ } -+ -+ np = of_parse_phandle(priv->dev->of_node, "memory-region", 0); -+ if (!np) { -+ dev_err(priv->dev, "can't find memory-region node\n"); -+ ret = -ENOMEM; -+ goto finish; -+ } ++ unsigned int rc = 1; ++ unsigned int pitch = 1; ++ unsigned int line_no = 1; ++ unsigned int line_size = op->len >> ++ XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT; ++ u64 cmd = XDMA_CMD_AST2500_CMD_IRQ_EN | XDMA_CMD_AST2500_CMD_IRQ_BMC | ++ XDMA_CMD_AST2500_CMD_ID; ++ u64 cmd_pitch = (op->direction ? XDMA_CMD_AST2500_PITCH_UPSTREAM : 0) | ++ XDMA_CMD_AST2500_PITCH_ID; + -+ rmem = of_reserved_mem_lookup(np); -+ of_node_put(np); -+ if (!rmem) { -+ dev_err(priv->dev, "can't find reserved memory.\n"); -+ ret = -ENOMEM; -+ goto finish; -+ } else { -+ priv->ssp_mem_phy_addr = rmem->base; -+ priv->ssp_mem_vir_addr = devm_ioremap(priv->dev, priv->ssp_mem_phy_addr, SSP_TOTAL_MEM_SZ); -+ if (!priv->ssp_mem_vir_addr) { -+ dev_err(priv->dev, "can't create reserved memory.\n"); -+ ret = -ENOMEM; -+ goto finish; -+ } else { -+ dev_info(priv->dev, "\nSSP memory: virt(0x%08x), phys(0x%08x)\n", -+ (uint32_t)priv->ssp_mem_vir_addr, priv->ssp_mem_phy_addr); -+ } -+ } ++ dev_dbg(ctx->dev, "xdma %s ast2500: bmc[%08llx] len[%08x] host[%08x]\n", ++ op->direction ? "upstream" : "downstream", bmc_addr, op->len, ++ (u32)op->host_addr); + -+ if (of_property_read_u32(np, "shm-size", &priv->ssp_shared_mem_size)) { -+ dev_err(priv->dev, "can't find shm-size property\n"); -+ ret = -ENOMEM; -+ goto finish; -+ } ++ if (op->len > XDMA_CMD_AST2500_CMD_LINE_SIZE) { ++ unsigned int rem; ++ unsigned int total; + -+ priv->ssp_shared_mem_vir_addr = priv->ssp_mem_vir_addr + SSP_TOTAL_MEM_SZ -+ - priv->ssp_shared_mem_size; -+ priv->ssp_shared_mem_phy_addr = priv->ssp_mem_phy_addr + SSP_TOTAL_MEM_SZ -+ - priv->ssp_shared_mem_size; -+ dev_info(priv->dev, "\nSSP shared memory: virt(0x%08x), phys(0x%08x), size(0x%08x)\n", -+ (uint32_t)priv->ssp_shared_mem_vir_addr, priv->ssp_shared_mem_phy_addr, -+ priv->ssp_shared_mem_size); ++ line_no = op->len / XDMA_CMD_AST2500_CMD_LINE_SIZE; ++ total = XDMA_CMD_AST2500_CMD_LINE_SIZE * line_no; ++ rem = (op->len - total) >> ++ XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT; ++ line_size = XDMA_CMD_AST2500_CMD_LINE_SIZE; ++ pitch = line_size >> XDMA_CMD_AST2500_PITCH_SHIFT; ++ line_size >>= XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT; + -+ if (request_firmware(&firmware, SSP_FILE_NAME, priv->dev) < 0) { -+ dev_err(priv->dev, "don't have %s\n", SSP_FILE_NAME); -+ release_firmware(firmware); -+ ret = -EINVAL; -+ goto finish; -+ } ++ if (rem) { ++ u32 rbmc = bmc_addr + total; + -+ memcpy(priv->ssp_mem_vir_addr, (void *)firmware->data, firmware->size); -+ release_firmware(firmware); ++ cmds[1].host_addr = op->host_addr + (u64)total; ++ cmds[1].pitch = cmd_pitch | ++ ((u64)rbmc & XDMA_CMD_AST2500_PITCH_ADDR) | ++ FIELD_PREP(XDMA_CMD_AST2500_PITCH_HOST, 1) | ++ FIELD_PREP(XDMA_CMD_AST2500_PITCH_BMC, 1); ++ cmds[1].cmd = cmd | ++ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_NO, 1) | ++ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_SIZE, ++ rem); ++ cmds[1].reserved = 0ULL; + -+ np = of_parse_phandle(mnode, "aspeed,cvic", 0); -+ if (!np) { -+ dev_err(priv->dev, "can't find CVIC\n"); -+ ret = -EINVAL; -+ goto finish; -+ } ++ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, ++ 16, 1, &cmds[1], sizeof(*cmds), ++ true); + -+ priv->cvic = devm_of_iomap(priv->dev, np, 0, NULL); -+ if (IS_ERR(priv->cvic)) { -+ dev_err(priv->dev, "can't map CVIC\n"); -+ ret = -EINVAL; -+ goto finish; -+ } ++ cmd &= ~(XDMA_CMD_AST2500_CMD_IRQ_EN | ++ XDMA_CMD_AST2500_CMD_IRQ_BMC); + -+ i = 0; -+ while (0 != (priv->irq[i] = irq_of_parse_and_map(mnode, i))) { -+ ret = request_irq(priv->irq[i], ast2600_ssp_interrupt, 0, -+ "ssp-sw-irq", priv); -+ i++; ++ rc++; ++ } + } -+ priv->n_irq = i; -+ dev_info(priv->dev, "%d ISRs registered\n", priv->n_irq); -+ -+ regmap_write(priv->scu, SSP_CTRL_REG, 0); -+ mdelay(1); -+ regmap_write(priv->scu, SSP_MEM_BASE_REG, priv->ssp_mem_phy_addr); -+ regmap_write(priv->scu, SSP_IMEM_LIMIT_REG, priv->ssp_mem_phy_addr + SSP_CACHED_MEM_SZ); -+ regmap_write(priv->scu, SSP_DMEM_LIMIT_REG, priv->ssp_mem_phy_addr + SSP_TOTAL_MEM_SZ); + -+ regmap_write(priv->scu, SSP_CACHE_RANGE_REG, SSP_CACHE_1ST_16MB_ENABLE); ++ cmds[0].host_addr = op->host_addr; ++ cmds[0].pitch = cmd_pitch | ++ (bmc_addr & XDMA_CMD_AST2500_PITCH_ADDR) | ++ FIELD_PREP(XDMA_CMD_AST2500_PITCH_HOST, pitch) | ++ FIELD_PREP(XDMA_CMD_AST2500_PITCH_BMC, pitch); ++ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_NO, line_no) | ++ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_SIZE, line_size); ++ cmds[0].reserved = 0ULL; + -+ regmap_write(priv->scu, SSP_CTRL_REG, SSP_CTRL_RESET_ASSERT); -+ mdelay(1); -+ regmap_write(priv->scu, SSP_CTRL_REG, 0); -+ mdelay(1); -+ regmap_write(priv->scu, SSP_CTRL_REG, SSP_CTRL_EN); ++ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, ++ sizeof(*cmds), true); + -+ dev_info(priv->dev, "Init successful\n"); -+ ret = 0; -+finish: -+ return ret; ++ return rc; +} + -+static void ast_ssp_remove(struct platform_device *pdev) ++static unsigned int aspeed_xdma_ast2600_set_cmd(struct aspeed_xdma *ctx, ++ struct aspeed_xdma_cmd cmds[2], ++ struct aspeed_xdma_op *op, ++ u64 bmc_addr) +{ -+ struct ast2600_ssp *priv = platform_get_drvdata(pdev); -+ int i; -+ -+ dev_info(priv->dev, "SSP module removed\n"); -+ regmap_write(priv->scu, SSP_CTRL_REG, 0); -+ for (i = 0; i < priv->n_irq; i++) -+ free_irq(priv->irq[i], priv); -+ -+ kfree(priv); -+ -+ misc_deregister((struct miscdevice *)&ast_ssp_misc); -+} -+ -+static const struct of_device_id of_ast_ssp_match_table[] = { -+ { .compatible = "aspeed,ast2600-ssp", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, of_ast_ssp_match_table); -+ -+static struct platform_driver ast_ssp_driver = { -+ .probe = ast_ssp_probe, -+ .remove = ast_ssp_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = of_ast_ssp_match_table, -+ }, -+}; ++ unsigned int rc = 1; ++ unsigned int pitch = 1; ++ unsigned int line_no = 1; ++ unsigned int line_size = op->len; ++ u64 cmd = XDMA_CMD_AST2600_CMD_IRQ_BMC | ++ (op->direction ? XDMA_CMD_AST2600_CMD_UPSTREAM : 0); + -+module_platform_driver(ast_ssp_driver); ++ if (op->host_addr & 0xffffffff00000000ULL || ++ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) ++ cmd |= XDMA_CMD_AST2600_CMD_64_EN; + -+MODULE_LICENSE("Dual BSD/GPL"); -diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c ---- a/drivers/soc/aspeed/aspeed-uart-routing.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-uart-routing.c 2025-12-23 10:16:21.125032653 +0000 -@@ -15,20 +15,30 @@ - #define HICRA 0x9c - - /* attributes options */ -+#define UART_ROUTING_IO0 "io0" - #define UART_ROUTING_IO1 "io1" - #define UART_ROUTING_IO2 "io2" - #define UART_ROUTING_IO3 "io3" - #define UART_ROUTING_IO4 "io4" - #define UART_ROUTING_IO5 "io5" - #define UART_ROUTING_IO6 "io6" -+#define UART_ROUTING_IO7 "io7" -+#define UART_ROUTING_IO8 "io8" -+#define UART_ROUTING_IO9 "io9" - #define UART_ROUTING_IO10 "io10" -+#define UART_ROUTING_IO12 "io12" -+#define UART_ROUTING_UART0 "uart0" - #define UART_ROUTING_UART1 "uart1" - #define UART_ROUTING_UART2 "uart2" - #define UART_ROUTING_UART3 "uart3" - #define UART_ROUTING_UART4 "uart4" - #define UART_ROUTING_UART5 "uart5" - #define UART_ROUTING_UART6 "uart6" -+#define UART_ROUTING_UART7 "uart7" -+#define UART_ROUTING_UART8 "uart8" -+#define UART_ROUTING_UART9 "uart9" - #define UART_ROUTING_UART10 "uart10" -+#define UART_ROUTING_UART12 "uart12" - #define UART_ROUTING_RES "reserved" - - struct aspeed_uart_routing { -@@ -488,6 +498,416 @@ - .attrs = ast2600_uart_routing_attrs, - }; - -+/* routing selector for AST27xx node 0 */ -+static struct aspeed_uart_routing_selector ast2700n0_uart9_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART9), -+ .reg = HICR9, -+ .shift = 12, -+ .mask = 0xf, -+ .options = { -+ UART_ROUTING_IO9, -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_RES, -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART12, -+ NULL, -+ }, -+}; ++ dev_dbg(ctx->dev, "xdma %s ast2600: bmc[%08llx] len[%08x] host[%016llx]\n", ++ op->direction ? "upstream" : "downstream", ++ bmc_addr, op->len, op->host_addr); + -+static struct aspeed_uart_routing_selector ast2700n0_io9_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO9), -+ .reg = HICR9, -+ .shift = 8, -+ .mask = 0xf, -+ .options = { -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART12, -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_RES, -+ UART_ROUTING_UART9, -+ NULL, -+ }, -+}; ++ if ((op->host_addr & 0xff) + op->len > XDMA_CMD_AST2600_CMD_LINE_SIZE) { ++ unsigned int rem; ++ unsigned int total; + -+static struct aspeed_uart_routing_selector ast2700n0_uart3_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART3), -+ .reg = HICRA, -+ .shift = 25, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO3, -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO2, -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ line_no = op->len / XDMA_CMD_AST2600_CMD_MULTILINE_SIZE; ++ total = XDMA_CMD_AST2600_CMD_MULTILINE_SIZE * line_no; ++ rem = op->len - total; ++ line_size = XDMA_CMD_AST2600_CMD_MULTILINE_SIZE; ++ pitch = line_size; + -+static struct aspeed_uart_routing_selector ast2700n0_uart2_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART2), -+ .reg = HICRA, -+ .shift = 22, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ if (rem) { ++ u32 rbmc = bmc_addr + total; + -+static struct aspeed_uart_routing_selector ast2700n0_uart1_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART1), -+ .reg = HICRA, -+ .shift = 19, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_IO0, -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART0, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ cmds[1].host_addr = op->host_addr + (u64)total; ++ cmds[1].pitch = ++ ((u64)rbmc & XDMA_CMD_AST2600_PITCH_ADDR) | ++ FIELD_PREP(XDMA_CMD_AST2600_PITCH_HOST, 1) | ++ FIELD_PREP(XDMA_CMD_AST2600_PITCH_BMC, 1); ++ cmds[1].cmd = cmd | ++ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_NO, 1) | ++ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_SIZE, ++ rem); ++ cmds[1].reserved = 0ULL; + -+static struct aspeed_uart_routing_selector ast2700n0_uart0_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART0), -+ .reg = HICRA, -+ .shift = 16, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, ++ 16, 1, &cmds[1], sizeof(*cmds), ++ true); + -+static struct aspeed_uart_routing_selector ast2700n0_io3_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO3), -+ .reg = HICRA, -+ .shift = 9, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART9, -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ cmd &= ~XDMA_CMD_AST2600_CMD_IRQ_BMC; + -+static struct aspeed_uart_routing_selector ast2700n0_io2_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO2), -+ .reg = HICRA, -+ .shift = 6, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART9, -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_IO0, -+ UART_ROUTING_IO1, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ rc++; ++ } ++ } + -+static struct aspeed_uart_routing_selector ast2700n0_io1_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO1), -+ .reg = HICRA, -+ .shift = 3, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART9, -+ UART_ROUTING_UART0, -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ cmds[0].host_addr = op->host_addr; ++ cmds[0].pitch = (bmc_addr & XDMA_CMD_AST2600_PITCH_ADDR) | ++ FIELD_PREP(XDMA_CMD_AST2600_PITCH_HOST, pitch) | ++ FIELD_PREP(XDMA_CMD_AST2600_PITCH_BMC, pitch); ++ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_NO, line_no) | ++ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_SIZE, line_size); ++ cmds[0].reserved = 0ULL; + -+static struct aspeed_uart_routing_selector ast2700n0_io0_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO0), -+ .reg = HICRA, -+ .shift = 0, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART0, -+ UART_ROUTING_UART1, -+ UART_ROUTING_UART2, -+ UART_ROUTING_UART3, -+ UART_ROUTING_UART9, -+ UART_ROUTING_IO2, -+ UART_ROUTING_IO3, -+ UART_ROUTING_IO9, -+ NULL, -+ }, -+}; ++ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, ++ sizeof(*cmds), true); + -+static struct attribute *ast2700n0_uart_routing_attrs[] = { -+ &ast2700n0_uart9_sel.dev_attr.attr, -+ &ast2700n0_io9_sel.dev_attr.attr, -+ &ast2700n0_uart3_sel.dev_attr.attr, -+ &ast2700n0_uart2_sel.dev_attr.attr, -+ &ast2700n0_uart1_sel.dev_attr.attr, -+ &ast2700n0_uart0_sel.dev_attr.attr, -+ &ast2700n0_io3_sel.dev_attr.attr, -+ &ast2700n0_io2_sel.dev_attr.attr, -+ &ast2700n0_io1_sel.dev_attr.attr, -+ &ast2700n0_io0_sel.dev_attr.attr, -+ NULL, -+}; ++ return rc; ++} + -+static const struct attribute_group ast2700n0_uart_routing_attr_group = { -+ .attrs = ast2700n0_uart_routing_attrs, -+}; ++static unsigned int aspeed_xdma_ast2700_set_cmd(struct aspeed_xdma *ctx, ++ struct aspeed_xdma_cmd cmds[2], ++ struct aspeed_xdma_op *op, ++ u64 bmc_addr) ++{ ++ unsigned int rc = 1; ++ unsigned int pitch = 1; ++ unsigned int line_no = 1; ++ unsigned int line_size = op->len; ++ u64 cmd = XDMA_CMD_AST2700_CMD_IRQ_BMC | ++ (op->direction ? XDMA_CMD_AST2700_CMD_UPSTREAM : 0); + -+/* routing selector for AST27xx node 1 */ -+static struct aspeed_uart_routing_selector ast2700n1_uart10_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART10), -+ .reg = HICR9, -+ .shift = 12, -+ .mask = 0xf, -+ .options = { -+ UART_ROUTING_IO10, -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_RES, -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART12, -+ NULL, -+ }, -+}; ++ if (op->host_addr & 0xffffffff00000000ULL || ++ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) ++ cmd |= XDMA_CMD_AST2700_CMD_64_EN; + -+static struct aspeed_uart_routing_selector ast2700n1_io10_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO10), -+ .reg = HICR9, -+ .shift = 8, -+ .mask = 0xf, -+ .options = { -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART12, -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_RES, -+ UART_ROUTING_UART10, -+ NULL, -+ }, -+}; ++ dev_dbg(ctx->dev, "xdma %s ast2700: bmc[%016llx] len[%08x] host[%016llx]\n", ++ op->direction ? "upstream" : "downstream", ++ bmc_addr, op->len, op->host_addr); + -+static struct aspeed_uart_routing_selector ast2700n1_uart8_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART8), -+ .reg = HICRA, -+ .shift = 25, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO8, -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO7, -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ if (op->len > XDMA_CMD_AST2700_CMD_LINE_SIZE) { ++ unsigned int rem; ++ unsigned int total; + -+static struct aspeed_uart_routing_selector ast2700n1_uart7_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART7), -+ .reg = HICRA, -+ .shift = 22, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ line_no = op->len / XDMA_CMD_AST2700_CMD_MULTILINE_SIZE; ++ total = XDMA_CMD_AST2700_CMD_MULTILINE_SIZE * line_no; ++ rem = op->len - total; ++ line_size = XDMA_CMD_AST2700_CMD_MULTILINE_SIZE; ++ pitch = line_size; + -+static struct aspeed_uart_routing_selector ast2700n1_uart6_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART6), -+ .reg = HICRA, -+ .shift = 19, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_IO5, -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART5, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ if (rem) { ++ u64 rbmc = bmc_addr + total; + -+static struct aspeed_uart_routing_selector ast2700n1_uart5_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_UART5), -+ .reg = HICRA, -+ .shift = 16, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ cmds[1].host_addr = op->host_addr + (u64)total; ++ cmds[1].pitch = ++ FIELD_PREP(XDMA_CMD_AST2700_PITCH_HOST, 1) | ++ FIELD_PREP(XDMA_CMD_AST2700_PITCH_BMC, 1); ++ cmds[1].cmd = cmd | ++ FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_NO, 1) | ++ FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_SIZE, ++ rem); ++ cmds[1].reserved = rbmc & XDMA_CMD_AST2700_BMC_ADDR; + -+static struct aspeed_uart_routing_selector ast2700n1_io8_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO8), -+ .reg = HICRA, -+ .shift = 9, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART10, -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, ++ 16, 1, &cmds[1], sizeof(*cmds), ++ true); + -+static struct aspeed_uart_routing_selector ast2700n1_io7_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO7), -+ .reg = HICRA, -+ .shift = 6, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART10, -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_IO5, -+ UART_ROUTING_IO6, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ cmd &= ~XDMA_CMD_AST2700_CMD_IRQ_BMC; + -+static struct aspeed_uart_routing_selector ast2700n1_io6_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO6), -+ .reg = HICRA, -+ .shift = 3, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART10, -+ UART_ROUTING_UART5, -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ rc++; ++ } ++ } ++ cmds[0].host_addr = op->host_addr; ++ cmds[0].pitch = ++ FIELD_PREP(XDMA_CMD_AST2700_PITCH_HOST, pitch) | ++ FIELD_PREP(XDMA_CMD_AST2700_PITCH_BMC, pitch); ++ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_NO, line_no) | ++ FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_SIZE, line_size); ++ cmds[0].reserved = bmc_addr & XDMA_CMD_AST2700_BMC_ADDR; + -+static struct aspeed_uart_routing_selector ast2700n1_io5_sel = { -+ .dev_attr = ROUTING_ATTR(UART_ROUTING_IO5), -+ .reg = HICRA, -+ .shift = 0, -+ .mask = 0x7, -+ .options = { -+ UART_ROUTING_UART5, -+ UART_ROUTING_UART6, -+ UART_ROUTING_UART7, -+ UART_ROUTING_UART8, -+ UART_ROUTING_UART10, -+ UART_ROUTING_IO7, -+ UART_ROUTING_IO8, -+ UART_ROUTING_IO10, -+ NULL, -+ }, -+}; ++ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, ++ sizeof(*cmds), true); + -+static struct attribute *ast2700n1_uart_routing_attrs[] = { -+ &ast2700n1_uart10_sel.dev_attr.attr, -+ &ast2700n1_io10_sel.dev_attr.attr, -+ &ast2700n1_uart8_sel.dev_attr.attr, -+ &ast2700n1_uart7_sel.dev_attr.attr, -+ &ast2700n1_uart6_sel.dev_attr.attr, -+ &ast2700n1_uart5_sel.dev_attr.attr, -+ &ast2700n1_io8_sel.dev_attr.attr, -+ &ast2700n1_io7_sel.dev_attr.attr, -+ &ast2700n1_io6_sel.dev_attr.attr, -+ &ast2700n1_io5_sel.dev_attr.attr, -+ NULL, -+}; ++ return rc; ++} + -+static const struct attribute_group ast2700n1_uart_routing_attr_group = { -+ .attrs = ast2700n1_uart_routing_attrs, -+}; ++static int aspeed_xdma_start(struct aspeed_xdma *ctx, unsigned int num_cmds, ++ struct aspeed_xdma_cmd cmds[2], bool upstream, ++ struct aspeed_xdma_client *client) ++{ ++ unsigned int i; ++ int rc = -EBUSY; ++ unsigned long flags; + - static ssize_t aspeed_uart_routing_show(struct device *dev, - struct device_attribute *attr, - char *buf) -@@ -580,6 +1000,10 @@ - .data = &ast2500_uart_routing_attr_group }, - { .compatible = "aspeed,ast2600-uart-routing", - .data = &ast2600_uart_routing_attr_group }, -+ { .compatible = "aspeed,ast2700n0-uart-routing", -+ .data = &ast2700n0_uart_routing_attr_group }, -+ { .compatible = "aspeed,ast2700n1-uart-routing", -+ .data = &ast2700n1_uart_routing_attr_group }, - { }, - }; - -@@ -589,7 +1013,7 @@ - .of_match_table = aspeed_uart_routing_table, - }, - .probe = aspeed_uart_routing_probe, -- .remove_new = aspeed_uart_routing_remove, -+ .remove = aspeed_uart_routing_remove, - }; - - module_platform_driver(aspeed_uart_routing_driver); -diff --git a/drivers/soc/aspeed/aspeed-udma.c b/drivers/soc/aspeed/aspeed-udma.c ---- a/drivers/soc/aspeed/aspeed-udma.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-udma.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,434 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright 2020 Aspeed Technology Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ spin_lock_irqsave(&ctx->engine_lock, flags); ++ if (ctx->in_reset) ++ goto unlock; ++ ++ spin_lock(&ctx->client_lock); ++ if (ctx->current_client) { ++ spin_unlock(&ctx->client_lock); ++ goto unlock; ++ } + -+#define DEVICE_NAME "aspeed-udma" ++ client->error = false; ++ client->in_progress = true; ++ ctx->current_client = client; ++ spin_unlock(&ctx->client_lock); + -+/* UART DMA registers offset */ -+#define UDMA_TX_DMA_EN 0x000 -+#define UDMA_RX_DMA_EN 0x004 -+#define UDMA_MISC 0x008 -+#define UDMA_MISC_RX_BUFSZ GENMASK(3, 2) -+#define UDMA_MISC_TX_BUFSZ GENMASK(1, 0) -+#define UDMA_TMOUT_TIMER 0x00c -+#define UDMA_TX_DMA_RST 0x020 -+#define UDMA_RX_DMA_RST 0x024 -+#define UDMA_TX_DMA_INT_EN 0x030 -+#define UDMA_TX_DMA_INT_STS 0x034 -+#define UDMA_RX_DMA_INT_EN 0x038 -+#define UDMA_RX_DMA_INT_STS 0x03c ++ ctx->upstream = upstream; ++ for (i = 0; i < num_cmds; ++i) { ++ trace_xdma_start(ctx, &cmds[i]); ++ /* ++ * Use memcpy_toio here to get some barriers before starting ++ * the operation. The command(s) need to be in physical memory ++ * before the XDMA engine starts. ++ */ ++ memcpy_toio(&ctx->cmdq[ctx->cmd_idx], &cmds[i], ++ sizeof(struct aspeed_xdma_cmd)); ++ ctx->cmd_idx = (ctx->cmd_idx + 1) % XDMA_NUM_CMDS; ++ } + -+#define UDMA_CHX_OFF(x) ((x) * 0x20) -+#define UDMA_CHX_TX_RD_PTR(x) (0x040 + UDMA_CHX_OFF(x)) -+#define UDMA_CHX_TX_WR_PTR(x) (0x044 + UDMA_CHX_OFF(x)) -+#define UDMA_CHX_TX_BUF_ADDR(x) (0x048 + UDMA_CHX_OFF(x)) -+#define UDMA_CHX_TX_CTRL(x) (0x04c + UDMA_CHX_OFF(x)) -+#define UDMA_TX_CTRL_BUF_ADDRH GENMASK(10, 8) -+#define UDMA_TX_CTRL_TMOUT_DIS BIT(4) -+#define UDMA_TX_CTRL_BUFSZ GENMASK(3, 0) -+#define UDMA_CHX_RX_RD_PTR(x) (0x050 + UDMA_CHX_OFF(x)) -+#define UDMA_CHX_RX_WR_PTR(x) (0x054 + UDMA_CHX_OFF(x)) -+#define UDMA_CHX_RX_BUF_ADDR(x) (0x058 + UDMA_CHX_OFF(x)) -+#define UDMA_CHX_RX_CTRL(x) (0x05c + UDMA_CHX_OFF(x)) -+#define UDMA_RX_CTRL_BUF_ADDRH GENMASK(10, 8) -+#define UDMA_RX_CTRL_TMOUT_DIS BIT(4) -+#define UDMA_RX_CTRL_BUFSZ GENMASK(1, 0) ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, ++ ctx->cmd_idx * ctx->chip->queue_entry_size); ++ rc = 0; + -+#define UDMA_MAX_CHANNEL 16 -+#define UDMA_TMOUT 0x200 ++unlock: ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ return rc; ++} + -+enum aspeed_udma_bufsz_code { -+ UDMA_BUFSZ_CODE_1KB, -+ UDMA_BUFSZ_CODE_4KB, -+ UDMA_BUFSZ_CODE_16KB, -+ UDMA_BUFSZ_CODE_64KB, -+}; ++static void aspeed_xdma_done(struct aspeed_xdma *ctx, bool error) ++{ ++ unsigned long flags; + -+struct aspeed_udma_chan { -+ dma_addr_t dma_addr; ++ spin_lock_irqsave(&ctx->client_lock, flags); ++ if (ctx->current_client) { ++ ctx->current_client->error = error; ++ ctx->current_client->in_progress = false; ++ ctx->current_client = NULL; ++ } ++ spin_unlock_irqrestore(&ctx->client_lock, flags); + -+ struct kfifo *fifo; -+ u32 fifo_sz; ++ wake_up_interruptible_all(&ctx->wait); ++} + -+ aspeed_udma_cb_t cb; -+ void *cb_arg; ++static irqreturn_t aspeed_xdma_irq(int irq, void *arg) ++{ ++ struct aspeed_xdma *ctx = arg; ++ u32 status; + -+ bool dis_tmout; -+}; ++ spin_lock(&ctx->engine_lock); ++ status = aspeed_xdma_readl(ctx, ctx->chip->regs.status); + -+struct aspeed_udma { -+ struct device *dev; -+ u8 __iomem *regs; -+ int irq; -+ struct aspeed_udma_chan tx_chs[UDMA_MAX_CHANNEL]; -+ struct aspeed_udma_chan rx_chs[UDMA_MAX_CHANNEL]; -+ spinlock_t lock; -+}; ++ trace_xdma_irq(status); + -+struct aspeed_udma udma[1]; ++ if (status & ctx->chip->status_bits.ds_dirty) { ++ aspeed_xdma_done(ctx, true); ++ } else { ++ if (status & ctx->chip->status_bits.us_comp) { ++ if (ctx->upstream) ++ aspeed_xdma_done(ctx, false); ++ } + -+static int aspeed_udma_get_bufsz_code(u32 buf_sz) -+{ -+ switch (buf_sz) { -+ case SZ_1K: -+ return UDMA_BUFSZ_CODE_1KB; -+ case SZ_4K: -+ return UDMA_BUFSZ_CODE_4KB; -+ case SZ_16K: -+ return UDMA_BUFSZ_CODE_16KB; -+ case SZ_64K: -+ return UDMA_BUFSZ_CODE_64KB; -+ default: -+ break; ++ if (status & ctx->chip->status_bits.ds_comp) { ++ if (!ctx->upstream) ++ aspeed_xdma_done(ctx, false); ++ } + } + -+ return -1; ++ aspeed_xdma_writel(ctx, ctx->chip->regs.status, status); ++ spin_unlock(&ctx->engine_lock); ++ ++ return IRQ_HANDLED; +} + -+static u32 aspeed_udma_get_tx_rptr(u32 ch_no) ++static void aspeed_xdma_reset(struct aspeed_xdma *ctx) +{ -+ return readl(udma->regs + UDMA_CHX_TX_RD_PTR(ch_no)); ++ unsigned long flags; ++ ++ trace_xdma_reset(ctx); ++ ++ reset_control_assert(ctx->reset); ++ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, ++ XDMA_ENGINE_SETUP_TIME_MAX_US); ++ reset_control_deassert(ctx->reset); ++ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, ++ XDMA_ENGINE_SETUP_TIME_MAX_US); ++ ++ aspeed_xdma_init_eng(ctx); ++ ++ aspeed_xdma_done(ctx, true); ++ ++ spin_lock_irqsave(&ctx->engine_lock, flags); ++ ctx->in_reset = false; ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ ++ wake_up_interruptible(&ctx->wait); +} + -+static u32 aspeed_udma_get_rx_wptr(u32 ch_no) ++static void aspeed_xdma_reset_work(struct work_struct *work) +{ -+ return readl(udma->regs + UDMA_CHX_RX_WR_PTR(ch_no)); ++ struct aspeed_xdma *ctx = container_of(work, struct aspeed_xdma, ++ reset_work); ++ ++ aspeed_xdma_reset(ctx); +} + -+static void aspeed_udma_set_ptr(u32 ch_no, u32 ptr, bool is_tx) ++static irqreturn_t aspeed_xdma_pcie_irq(int irq, void *arg) +{ -+ writel(ptr, udma->regs + -+ ((is_tx) ? UDMA_CHX_TX_WR_PTR(ch_no) : UDMA_CHX_RX_RD_PTR(ch_no))); ++ struct aspeed_xdma *ctx = arg; ++ ++ trace_xdma_perst(ctx); ++ ++ spin_lock(&ctx->engine_lock); ++ if (ctx->in_reset) { ++ spin_unlock(&ctx->engine_lock); ++ return IRQ_HANDLED; ++ } ++ ++ ctx->in_reset = true; ++ spin_unlock(&ctx->engine_lock); ++ ++ schedule_work(&ctx->reset_work); ++ return IRQ_HANDLED; +} + -+void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr) ++static ssize_t aspeed_xdma_write(struct file *file, const char __user *buf, ++ size_t len, loff_t *offset) +{ -+ aspeed_udma_set_ptr(ch_no, wptr, true); ++ int rc; ++ unsigned int num_cmds; ++ struct aspeed_xdma_op op; ++ struct aspeed_xdma_cmd cmds[2]; ++ struct aspeed_xdma_client *client = file->private_data; ++ struct aspeed_xdma *ctx = client->ctx; ++ ++ if (len != sizeof(op)) ++ return -EINVAL; ++ ++ if (READ_ONCE(client->in_progress)) ++ return -EBUSY; ++ ++ if (copy_from_user(&op, buf, len)) ++ return -EFAULT; ++ ++ if (!op.len || op.len > client->size || ++ op.direction > ASPEED_XDMA_DIRECTION_UPSTREAM) ++ return -EINVAL; ++ ++ num_cmds = ctx->chip->set_cmd(ctx, cmds, &op, client->phys); ++ do { ++ rc = aspeed_xdma_start(ctx, num_cmds, cmds, !!op.direction, ++ client); ++ if (!rc) ++ break; ++ ++ if ((file->f_flags & O_NONBLOCK) || rc != -EBUSY) ++ return rc; ++ ++ rc = wait_event_interruptible(ctx->wait, ++ !(ctx->current_client || ++ ctx->in_reset)); ++ } while (!rc); ++ ++ if (rc) ++ return -EINTR; ++ ++ if (!(file->f_flags & O_NONBLOCK)) { ++ rc = wait_event_interruptible(ctx->wait, !client->in_progress); ++ if (rc) ++ return -EINTR; ++ ++ if (client->error) ++ return -EIO; ++ } ++ ++ return len; +} -+EXPORT_SYMBOL(aspeed_udma_set_tx_wptr); + -+void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr) ++static __poll_t aspeed_xdma_poll(struct file *file, ++ struct poll_table_struct *wait) +{ -+ aspeed_udma_set_ptr(ch_no, rptr, false); ++ __poll_t mask = 0; ++ __poll_t req = poll_requested_events(wait); ++ struct aspeed_xdma_client *client = file->private_data; ++ struct aspeed_xdma *ctx = client->ctx; ++ ++ if (req & (EPOLLIN | EPOLLRDNORM)) { ++ if (READ_ONCE(client->in_progress)) ++ poll_wait(file, &ctx->wait, wait); ++ ++ if (!READ_ONCE(client->in_progress)) { ++ if (READ_ONCE(client->error)) ++ mask |= EPOLLERR; ++ else ++ mask |= EPOLLIN | EPOLLRDNORM; ++ } ++ } ++ ++ if (req & (EPOLLOUT | EPOLLWRNORM)) { ++ if (READ_ONCE(ctx->current_client)) ++ poll_wait(file, &ctx->wait, wait); ++ ++ if (!READ_ONCE(ctx->current_client)) ++ mask |= EPOLLOUT | EPOLLWRNORM; ++ } ++ ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ // 2600 and older IC do reset here will trigger unexpected irq. ++ // Only do it for 2700. ++ if (mask) ++ aspeed_xdma_reset(ctx); ++#endif ++ ++ return mask; +} -+EXPORT_SYMBOL(aspeed_udma_set_rx_rptr); + -+static int aspeed_udma_free_chan(u32 ch_no, bool is_tx) ++static long aspeed_xdma_ioctl(struct file *file, unsigned int cmd, ++ unsigned long param) +{ -+ u32 reg; + unsigned long flags; ++ struct aspeed_xdma_client *client = file->private_data; ++ struct aspeed_xdma *ctx = client->ctx; + -+ if (ch_no > UDMA_MAX_CHANNEL) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&udma->lock, flags); ++ switch (cmd) { ++ case ASPEED_XDMA_IOCTL_RESET: ++ spin_lock_irqsave(&ctx->engine_lock, flags); ++ if (ctx->in_reset) { ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ return 0; ++ } + -+ reg = readl(udma->regs + -+ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); -+ reg &= ~(0x1 << ch_no); ++ ctx->in_reset = true; ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); + -+ writel(reg, udma->regs + -+ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); ++ if (READ_ONCE(ctx->current_client)) ++ dev_warn(ctx->dev, ++ "User reset with transfer in progress.\n"); + -+ spin_unlock_irqrestore(&udma->lock, flags); ++ aspeed_xdma_reset(ctx); ++ break; ++ default: ++ return -EINVAL; ++ } + + return 0; +} + -+int aspeed_udma_free_tx_chan(u32 ch_no) ++static void aspeed_xdma_vma_close(struct vm_area_struct *vma) +{ -+ return aspeed_udma_free_chan(ch_no, true); -+} -+EXPORT_SYMBOL(aspeed_udma_free_tx_chan); ++ int rc; ++ struct aspeed_xdma_client *client = vma->vm_private_data; + -+int aspeed_udma_free_rx_chan(u32 ch_no) -+{ -+ return aspeed_udma_free_chan(ch_no, false); ++ rc = wait_event_interruptible(client->ctx->wait, !client->in_progress); ++ if (rc) ++ return; ++ ++ gen_pool_free(client->ctx->pool, (unsigned long)client->virt, ++ client->size); ++ trace_xdma_unmap(client); ++ ++ client->virt = NULL; ++ client->phys = 0; ++ client->size = 0; +} -+EXPORT_SYMBOL(aspeed_udma_free_rx_chan); + -+static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, -+ struct kfifo *fifo, u32 fifo_sz, -+ aspeed_udma_cb_t cb, void *id, bool dis_tmout, bool is_tx) ++static const struct vm_operations_struct aspeed_xdma_vm_ops = { ++ .close = aspeed_xdma_vma_close, ++}; ++ ++static int aspeed_xdma_mmap(struct file *file, struct vm_area_struct *vma) +{ -+ int retval = 0; -+ int fifosz_code; ++ int rc; ++ struct aspeed_xdma_client *client = file->private_data; ++ struct aspeed_xdma *ctx = client->ctx; + -+ u32 reg; -+ unsigned long flags; -+ struct aspeed_udma_chan *ch; ++ /* restrict file to one mapping */ ++ if (client->size) ++ return -EBUSY; + -+ if (ch_no > UDMA_MAX_CHANNEL) { -+ retval = -EINVAL; -+ goto out; ++ client->size = vma->vm_end - vma->vm_start; ++ client->virt = gen_pool_dma_alloc(ctx->pool, client->size, ++ &client->phys); ++ if (!client->virt) { ++ trace_xdma_mmap_error(client, 0UL); ++ client->phys = 0; ++ client->size = 0; ++ return -ENOMEM; + } + -+ if (IS_ERR_OR_NULL(fifo) || IS_ERR_OR_NULL(fifo->kfifo.data)) { -+ retval = -EINVAL; -+ goto out; -+ } ++ vma->vm_pgoff = (client->phys - ctx->mem_phys) >> PAGE_SHIFT; ++ vma->vm_ops = &aspeed_xdma_vm_ops; ++ vma->vm_private_data = client; ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + -+ fifosz_code = aspeed_udma_get_bufsz_code(fifo_sz); -+ if (fifosz_code < 0) { -+ retval = -EINVAL; -+ goto out; -+ } ++ rc = io_remap_pfn_range(vma, vma->vm_start, client->phys >> PAGE_SHIFT, ++ client->size, vma->vm_page_prot); ++ if (rc) { ++ dev_warn(ctx->dev, "mmap err: v[%08lx] to p[%pa], s[%08x]\n", ++ vma->vm_start, &client->phys, client->size); + -+ spin_lock_irqsave(&udma->lock, flags); ++ gen_pool_free(ctx->pool, (unsigned long)client->virt, ++ client->size); + -+ if (is_tx) { -+ reg = readl(udma->regs + UDMA_TX_DMA_INT_EN); -+ if (reg & (0x1 << ch_no)) { -+ retval = -EBUSY; -+ goto unlock_n_out; -+ } ++ trace_xdma_mmap_error(client, vma->vm_start); ++ client->virt = NULL; ++ client->phys = 0; ++ client->size = 0; ++ return rc; ++ } + -+ reg |= (0x1 << ch_no); -+ writel(reg, udma->regs + UDMA_TX_DMA_INT_EN); ++ trace_xdma_mmap(client); ++ dev_dbg(ctx->dev, "mmap: v[%08lx] to p[%pa], s[%08x]\n", ++ vma->vm_start, &client->phys, client->size); + -+ reg = FIELD_PREP(UDMA_TX_CTRL_BUF_ADDRH, (u64)addr >> 32) | -+ ((dis_tmout) ? UDMA_TX_CTRL_TMOUT_DIS : 0) | -+ FIELD_PREP(UDMA_TX_CTRL_BUFSZ, fifosz_code); -+ writel(reg, udma->regs + UDMA_CHX_TX_CTRL(ch_no)); ++ return 0; ++} + -+ writel(addr, udma->regs + UDMA_CHX_TX_BUF_ADDR(ch_no)); -+ } else { -+ reg = readl(udma->regs + UDMA_RX_DMA_INT_EN); -+ if (reg & (0x1 << ch_no)) { -+ retval = -EBUSY; -+ goto unlock_n_out; -+ } ++static int aspeed_xdma_open(struct inode *inode, struct file *file) ++{ ++ struct miscdevice *misc = file->private_data; ++ struct aspeed_xdma *ctx = container_of(misc, struct aspeed_xdma, misc); ++ struct aspeed_xdma_client *client = kzalloc(sizeof(*client), ++ GFP_KERNEL); + -+ reg |= (0x1 << ch_no); -+ writel(reg, udma->regs + UDMA_RX_DMA_INT_EN); ++ if (!client) ++ return -ENOMEM; + -+ reg = FIELD_PREP(UDMA_RX_CTRL_BUF_ADDRH, (u64)addr >> 32) | -+ ((dis_tmout) ? UDMA_RX_CTRL_TMOUT_DIS : 0) | -+ FIELD_PREP(UDMA_RX_CTRL_BUFSZ, fifosz_code); -+ writel(reg, udma->regs + UDMA_CHX_RX_CTRL(ch_no)); ++ kobject_get(&ctx->kobj); ++ client->ctx = ctx; ++ file->private_data = client; ++ return 0; ++} + -+ writel(addr, udma->regs + UDMA_CHX_RX_BUF_ADDR(ch_no)); ++static int aspeed_xdma_release(struct inode *inode, struct file *file) ++{ ++ bool reset = false; ++ unsigned long flags; ++ struct aspeed_xdma_client *client = file->private_data; ++ struct aspeed_xdma *ctx = client->ctx; ++ ++ spin_lock_irqsave(&ctx->client_lock, flags); ++ if (client == ctx->current_client) { ++ spin_lock(&ctx->engine_lock); ++ if (ctx->in_reset) { ++ ctx->current_client = NULL; ++ } else { ++ ctx->in_reset = true; ++ reset = true; ++ } ++ spin_unlock(&ctx->engine_lock); + } ++ spin_unlock_irqrestore(&ctx->client_lock, flags); + -+ ch = (is_tx) ? &udma->tx_chs[ch_no] : &udma->rx_chs[ch_no]; -+ ch->fifo = fifo; -+ ch->fifo_sz = fifo_sz; -+ ch->cb = cb; -+ ch->cb_arg = id; -+ ch->dma_addr = addr; -+ ch->dis_tmout = dis_tmout; ++ if (reset) ++ aspeed_xdma_reset(ctx); + -+unlock_n_out: -+ spin_unlock_irqrestore(&udma->lock, flags); -+out: ++ if (client->virt) { ++ gen_pool_free(ctx->pool, (unsigned long)client->virt, ++ client->size); ++ trace_xdma_unmap(client); ++ } ++ ++ kfree(client); ++ kobject_put(&ctx->kobj); + return 0; +} + -+int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, -+ struct kfifo *fifo, u32 fifo_sz, -+ aspeed_udma_cb_t cb, void *id, bool dis_tmout) ++static const struct file_operations aspeed_xdma_fops = { ++ .owner = THIS_MODULE, ++ .write = aspeed_xdma_write, ++ .poll = aspeed_xdma_poll, ++ .unlocked_ioctl = aspeed_xdma_ioctl, ++ .mmap = aspeed_xdma_mmap, ++ .open = aspeed_xdma_open, ++ .release = aspeed_xdma_release, ++}; ++ ++static int aspeed_xdma_init_scu(struct aspeed_xdma *ctx, struct device *dev) +{ -+ return aspeed_udma_request_chan(ch_no, addr, fifo, fifo_sz, cb, id, -+ dis_tmout, true); -+} -+EXPORT_SYMBOL(aspeed_udma_request_tx_chan); ++ struct regmap *scu = syscon_regmap_lookup_by_phandle(dev->of_node, ++ "aspeed,scu"); ++ ++ if (!IS_ERR(scu)) { ++ u32 selection; ++ bool pcie_device_bmc = true; ++ const u32 bmc = SCU_PCIE_CONF_BMC_EN | ++ SCU_PCIE_CONF_BMC_EN_MSI | SCU_PCIE_CONF_BMC_EN_IRQ | ++ SCU_PCIE_CONF_BMC_EN_DMA; ++ const u32 vga = SCU_PCIE_CONF_VGA_EN | ++ SCU_PCIE_CONF_VGA_EN_MSI | SCU_PCIE_CONF_VGA_EN_IRQ | ++ SCU_PCIE_CONF_VGA_EN_DMA; ++ const char *pcie = NULL; ++ ++ if (!of_property_read_string(dev->of_node, ++ "aspeed,pcie-device", &pcie)) { ++ if (!strcmp(pcie, "vga")) { ++ pcie_device_bmc = false; ++ } else if (strcmp(pcie, "bmc")) { ++ dev_err(dev, ++ "Invalid pcie-device property %s.\n", ++ pcie); ++ return -EINVAL; ++ } ++ } ++ ++ if (pcie_device_bmc) { ++ selection = bmc; ++ regmap_update_bits(scu, ctx->chip->scu_bmc_class, ++ SCU_BMC_CLASS_REV_MASK, ++ SCU_BMC_CLASS_REV_XDMA); ++ } else { ++ selection = vga; ++ } ++ ++ regmap_update_bits(scu, ctx->chip->scu_pcie_conf, bmc | vga, ++ selection); ++ ++ if (ctx->chip->scu_misc_ctrl) { ++ regmap_update_bits(scu, ctx->chip->scu_misc_ctrl, ++ ctx->chip->scu_misc_mask, ++ ctx->chip->scu_misc_mask); ++ ++ regmap_update_bits(scu, SCU_AST2600_DEBUG_CTRL, ++ ctx->chip->scu_disable_mask, 0); ++ } ++ ++ if (ctx->chip->scu_pcie_ctrl) { ++ regmap_update_bits(scu, ctx->chip->scu_pcie_ctrl, ++ SCU_AST2700_PCIE_CTRL_DMA_EN, ++ SCU_AST2700_PCIE_CTRL_DMA_EN); ++ } ++ } else { ++ dev_warn(dev, "Unable to configure PCIe: %ld; continuing.\n", ++ PTR_ERR(scu)); ++ } + -+int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, -+ struct kfifo *fifo, u32 fifo_sz, -+ aspeed_udma_cb_t cb, void *id, bool dis_tmout) -+{ -+ return aspeed_udma_request_chan(ch_no, addr, fifo, fifo_sz, cb, id, -+ dis_tmout, false); ++ return 0; +} -+EXPORT_SYMBOL(aspeed_udma_request_rx_chan); + -+static void aspeed_udma_chan_ctrl(u32 ch_no, u32 op, bool is_tx) ++static void aspeed_xdma_kobject_release(struct kobject *kobj) +{ -+ unsigned long flags; -+ u32 reg_en, reg_rst; -+ u32 reg_en_off = (is_tx) ? UDMA_TX_DMA_EN : UDMA_RX_DMA_EN; -+ u32 reg_rst_off = (is_tx) ? UDMA_TX_DMA_RST : UDMA_TX_DMA_RST; -+ -+ if (ch_no > UDMA_MAX_CHANNEL) -+ return; ++ struct aspeed_xdma *ctx = container_of(kobj, struct aspeed_xdma, kobj); + -+ spin_lock_irqsave(&udma->lock, flags); ++ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE); + -+ reg_en = readl(udma->regs + reg_en_off); -+ reg_rst = readl(udma->regs + reg_rst_off); ++ gen_pool_destroy(ctx->pool); + -+ switch (op) { -+ case ASPEED_UDMA_OP_ENABLE: -+ reg_en |= (0x1 << ch_no); -+ writel(reg_en, udma->regs + reg_en_off); -+ break; -+ case ASPEED_UDMA_OP_DISABLE: -+ reg_en &= ~(0x1 << ch_no); -+ writel(reg_en, udma->regs + reg_en_off); -+ break; -+ case ASPEED_UDMA_OP_RESET: -+ reg_en &= ~(0x1 << ch_no); -+ writel(reg_en, udma->regs + reg_en_off); ++ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt, ++ ctx->mem_coherent); ++} + -+ reg_rst |= (0x1 << ch_no); -+ writel(reg_rst, udma->regs + reg_rst_off); ++static const struct kobj_type aspeed_xdma_kobject_type = { ++ .release = aspeed_xdma_kobject_release, ++}; + -+ udelay(100); ++static int aspeed_xdma_probe(struct platform_device *pdev) ++{ ++ int rc, id; ++ struct aspeed_xdma *ctx; ++ struct reserved_mem *mem; ++ struct device *dev = &pdev->dev; ++ struct device_node *memory_region; ++ const void *md = of_device_get_match_data(dev); ++ bool rc_f; + -+ reg_rst &= ~(0x1 << ch_no); -+ writel(reg_rst, udma->regs + reg_rst_off); -+ break; -+ default: -+ break; -+ } ++ if (!md) ++ return -ENODEV; + -+ spin_unlock_irqrestore(&udma->lock, flags); -+} ++ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; + -+void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) -+{ -+ aspeed_udma_chan_ctrl(ch_no, op, true); -+} -+EXPORT_SYMBOL(aspeed_udma_tx_chan_ctrl); ++ ctx->chip = md; ++ ctx->dev = dev; ++ platform_set_drvdata(pdev, ctx); ++ spin_lock_init(&ctx->client_lock); ++ spin_lock_init(&ctx->engine_lock); ++ INIT_WORK(&ctx->reset_work, aspeed_xdma_reset_work); ++ init_waitqueue_head(&ctx->wait); + -+void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) -+{ -+ aspeed_udma_chan_ctrl(ch_no, op, false); -+} -+EXPORT_SYMBOL(aspeed_udma_rx_chan_ctrl); ++ rc_f = of_find_property(dev->of_node, "pcie_rc", NULL) ? 1 : 0; + -+static irqreturn_t aspeed_udma_isr(int irq, void *arg) -+{ -+ u32 bit; -+ unsigned long tx_sts = readl(udma->regs + UDMA_TX_DMA_INT_STS); -+ unsigned long rx_sts = readl(udma->regs + UDMA_RX_DMA_INT_STS); ++ ctx->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(ctx->base)) ++ return PTR_ERR(ctx->base); + -+ if (udma != (struct aspeed_udma *)arg) -+ return IRQ_NONE; ++ ctx->irq = platform_get_irq(pdev, 0); ++ if (ctx->irq < 0) { ++ dev_err(dev, "Failed to find IRQ.\n"); ++ return ctx->irq; ++ } + -+ if (tx_sts == 0 && rx_sts == 0) -+ return IRQ_NONE; ++ ctx->pcie_irq = platform_get_irq(pdev, 1); ++ if (ctx->pcie_irq < 0) ++ return ctx->pcie_irq; + -+ for_each_set_bit(bit, &tx_sts, UDMA_MAX_CHANNEL) { -+ writel((0x1 << bit), udma->regs + UDMA_TX_DMA_INT_STS); -+ if (udma->tx_chs[bit].cb) -+ udma->tx_chs[bit].cb(aspeed_udma_get_tx_rptr(bit), -+ udma->tx_chs[bit].cb_arg); ++ rc = devm_request_irq(dev, ctx->irq, aspeed_xdma_irq, 0, ++ dev_name(dev), ctx); ++ if (rc < 0) { ++ dev_err(dev, "Failed to request IRQ %d.\n", ctx->irq); ++ return rc; + } + -+ for_each_set_bit(bit, &rx_sts, UDMA_MAX_CHANNEL) { -+ writel((0x1 << bit), udma->regs + UDMA_RX_DMA_INT_STS); -+ if (udma->rx_chs[bit].cb) -+ udma->rx_chs[bit].cb(aspeed_udma_get_rx_wptr(bit), -+ udma->rx_chs[bit].cb_arg); ++ ctx->clock = devm_clk_get(dev, NULL); ++ if (IS_ERR(ctx->clock)) { ++ dev_err(dev, "Failed to request clock.\n"); ++ return PTR_ERR(ctx->clock); + } + -+ return IRQ_HANDLED; -+} ++ ctx->reset = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(ctx->reset)) { ++ dev_err(dev, "Failed to request reset control.\n"); ++ return PTR_ERR(ctx->reset); ++ } + -+static int aspeed_udma_probe(struct platform_device *pdev) -+{ -+ int i, rc; -+ uint32_t reg; -+ struct resource *res; -+ struct device *dev = &pdev->dev; ++ if (rc_f) { ++ ctx->reset_rc = devm_reset_control_get_exclusive(dev, "root-complex"); ++ if (IS_ERR(ctx->reset_rc)) { ++ dev_dbg(dev, "Failed to request reset RC control.\n"); ++ ctx->reset_rc = NULL; ++ } ++ } + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (IS_ERR_OR_NULL(res)) { -+ dev_err(dev, "failed to get register base\n"); -+ return -ENODEV; ++ memory_region = of_parse_phandle(dev->of_node, "memory-region", 0); ++ if (!memory_region) { ++ dev_err(dev, "Failed to find memory-region.\n"); ++ rc = -ENOMEM; ++ return rc; + } + -+ udma->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR_OR_NULL(udma->regs)) { -+ dev_err(dev, "failed to map registers\n"); -+ return PTR_ERR(udma->regs); ++ mem = of_reserved_mem_lookup(memory_region); ++ of_node_put(memory_region); ++ if (!mem) { ++ dev_err(dev, "Failed to find reserved memory.\n"); ++ rc = -ENOMEM; ++ return rc; + } + -+ /* disable for safety */ -+ writel(0x0, udma->regs + UDMA_TX_DMA_EN); -+ writel(0x0, udma->regs + UDMA_RX_DMA_EN); ++ ctx->mem_phys = mem->base; ++ ctx->mem_size = mem->size; + -+ udma->irq = platform_get_irq(pdev, 0); -+ if (udma->irq < 0) { -+ dev_err(dev, "failed to get IRQ number\n"); -+ return -ENODEV; ++ rc = of_reserved_mem_device_init(dev); ++ if (rc) { ++ dev_err(dev, "Failed to init reserved memory.\n"); ++ return rc; + } + -+ rc = devm_request_irq(dev, udma->irq, aspeed_udma_isr, -+ IRQF_SHARED, DEVICE_NAME, udma); ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (rc) { -+ dev_err(dev, "failed to request IRQ handler\n"); ++ dev_err(dev, "Failed to mask DMA.\n"); + return rc; + } + -+ /* -+ * For legacy design. -+ * - TX ringbuffer size: 4KB -+ * - RX ringbuffer size: 64KB -+ * - Timeout timer disabled -+ */ -+ reg = FIELD_PREP(UDMA_MISC_TX_BUFSZ, UDMA_BUFSZ_CODE_4KB) | -+ FIELD_PREP(UDMA_MISC_RX_BUFSZ, UDMA_BUFSZ_CODE_64KB); -+ writel(reg, udma->regs + UDMA_MISC); ++ ctx->mem_virt = dma_alloc_coherent(dev, ctx->mem_size, ++ &ctx->mem_coherent, __GFP_NOWARN); ++ if (!ctx->mem_virt) { ++ dev_err(dev, "Failed to allocate reserved memory.\n"); ++ rc = -ENOMEM; ++ return rc; ++ } + -+ for (i = 0; i < UDMA_MAX_CHANNEL; ++i) { -+ writel(0, udma->regs + UDMA_CHX_TX_WR_PTR(i)); -+ writel(0, udma->regs + UDMA_CHX_RX_RD_PTR(i)); ++ ctx->pool = gen_pool_create(ilog2(PAGE_SIZE), -1); ++ if (!ctx->pool) { ++ dev_err(dev, "Failed to setup genalloc pool.\n"); ++ rc = -ENOMEM; ++ goto err_nopool; + } + -+ writel(0xffffffff, udma->regs + UDMA_TX_DMA_RST); -+ writel(0x0, udma->regs + UDMA_TX_DMA_RST); ++ rc = gen_pool_add_virt(ctx->pool, (unsigned long)ctx->mem_virt, ++ ctx->mem_phys, ctx->mem_size, -1); ++ if (rc) { ++ dev_err(ctx->dev, "Failed to add memory to genalloc pool.\n"); ++ goto err_pool_scu_clk; ++ } + -+ writel(0xffffffff, udma->regs + UDMA_RX_DMA_RST); -+ writel(0x0, udma->regs + UDMA_RX_DMA_RST); ++ rc = aspeed_xdma_init_scu(ctx, dev); ++ if (rc) ++ goto err_pool_scu_clk; + -+ writel(0x0, udma->regs + UDMA_TX_DMA_INT_EN); -+ writel(0xffffffff, udma->regs + UDMA_TX_DMA_INT_STS); -+ writel(0x0, udma->regs + UDMA_RX_DMA_INT_EN); -+ writel(0xffffffff, udma->regs + UDMA_RX_DMA_INT_STS); ++ rc = clk_prepare_enable(ctx->clock); ++ if (rc) { ++ dev_err(dev, "Failed to enable the clock.\n"); ++ goto err_pool_scu_clk; ++ } + -+ writel(UDMA_TMOUT, udma->regs + UDMA_TMOUT_TIMER); ++ if (ctx->reset_rc) { ++ rc = reset_control_deassert(ctx->reset_rc); ++ if (rc) { ++ dev_err(dev, "Failed to clear the RC reset.\n"); ++ goto err_reset_rc; ++ } ++ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, ++ XDMA_ENGINE_SETUP_TIME_MAX_US); ++ } + -+ spin_lock_init(&udma->lock); ++ rc = reset_control_deassert(ctx->reset); ++ if (rc) { ++ dev_err(dev, "Failed to clear the reset.\n"); ++ goto err_reset; ++ } ++ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, ++ XDMA_ENGINE_SETUP_TIME_MAX_US); + -+ dev_set_drvdata(dev, udma); ++ ctx->cmdq = gen_pool_dma_alloc(ctx->pool, XDMA_CMDQ_SIZE, ++ &ctx->cmdq_phys); ++ if (!ctx->cmdq) { ++ dev_err(ctx->dev, "Failed to genalloc cmdq.\n"); ++ rc = -ENOMEM; ++ goto err_pool; ++ } + -+ return 0; -+} ++ aspeed_xdma_init_eng(ctx); + -+static const struct of_device_id aspeed_udma_match[] = { -+ { .compatible = "aspeed,ast2500-udma" }, -+ { .compatible = "aspeed,ast2600-udma" }, -+ { .compatible = "aspeed,ast2700-udma" }, -+ { }, -+}; ++ id = of_alias_get_id(dev->of_node, "xdma"); ++ if (id < 0) ++ id = 0; + -+static struct platform_driver aspeed_udma_driver = { -+ .driver = { -+ .name = DEVICE_NAME, -+ .of_match_table = aspeed_udma_match, ++ ctx->misc.minor = MISC_DYNAMIC_MINOR; ++ ctx->misc.fops = &aspeed_xdma_fops; ++ ctx->misc.name = kasprintf(GFP_KERNEL, "%s%d", DEVICE_NAME, id); ++ ctx->misc.parent = dev; ++ rc = misc_register(&ctx->misc); ++ if (rc) { ++ dev_err(dev, "Failed to register xdma miscdevice.\n"); ++ goto err_misc; ++ } + -+ }, -+ .probe = aspeed_udma_probe, -+}; ++ /* ++ * This interrupt could fire immediately so only request it once the ++ * engine and driver are initialized. ++ */ ++ rc = devm_request_irq(dev, ctx->pcie_irq, aspeed_xdma_pcie_irq, ++ IRQF_SHARED, dev_name(dev), ctx); ++ if (rc) ++ return rc; + -+module_platform_driver(aspeed_udma_driver); ++ kobject_init(&ctx->kobj, &aspeed_xdma_kobject_type); ++ return 0; + -+MODULE_AUTHOR("Chia-Wei Wang "); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Aspeed UDMA Engine Driver"); -diff --git a/drivers/soc/aspeed/aspeed-usb-hp.c b/drivers/soc/aspeed/aspeed-usb-hp.c ---- a/drivers/soc/aspeed/aspeed-usb-hp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-usb-hp.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,152 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2021 Aspeed Technology Inc. -+ */ ++err_misc: ++ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE); ++err_pool: ++ reset_control_assert(ctx->reset); ++err_reset: ++ if (ctx->reset_rc) ++ reset_control_assert(ctx->reset_rc); ++err_reset_rc: ++ clk_disable_unprepare(ctx->clock); ++err_pool_scu_clk: ++ gen_pool_destroy(ctx->pool); ++err_nopool: ++ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt, ++ ctx->mem_coherent); ++ return rc; ++} + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++static void aspeed_xdma_remove(struct platform_device *pdev) ++{ ++ struct aspeed_xdma *ctx = platform_get_drvdata(pdev); + -+#define USB_HP_BEHCI84 0x84 /* Controller Fine-tune Register */ ++ reset_control_assert(ctx->reset); ++ if (ctx->reset_rc) ++ reset_control_assert(ctx->reset_rc); ++ clk_disable_unprepare(ctx->clock); + -+static const struct of_device_id aspeed_usb_hp_dt_ids[] = { -+ { -+ .compatible = "aspeed,ast2600-usb2ahp", -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb3ahp", ++ aspeed_xdma_done(ctx, true); ++ ++ misc_deregister(&ctx->misc); ++ kobject_put(&ctx->kobj); ++} ++ ++static const struct aspeed_xdma_chip aspeed_ast2500_xdma_chip = { ++ .control = XDMA_AST2500_CTRL_US_COMP | XDMA_AST2500_CTRL_DS_COMP | ++ XDMA_AST2500_CTRL_DS_DIRTY | XDMA_AST2500_CTRL_DS_SIZE_256 | ++ XDMA_AST2500_CTRL_DS_TIMEOUT | XDMA_AST2500_CTRL_DS_CHECK_ID, ++ .scu_bmc_class = SCU_AST2500_BMC_CLASS_REV, ++ .scu_misc_ctrl = 0, ++ .scu_pcie_conf = SCU_AST2500_PCIE_CONF, ++ .scu_pcie_ctrl = 0, ++ .queue_entry_size = XDMA_AST2500_QUEUE_ENTRY_SIZE, ++ .regs = { ++ .bmc_cmdq_addr = XDMA_AST2500_BMC_CMDQ_ADDR, ++ .bmc_cmdq_addr_ext = 0, ++ .bmc_cmdq_endp = XDMA_AST2500_BMC_CMDQ_ENDP, ++ .bmc_cmdq_writep = XDMA_AST2500_BMC_CMDQ_WRITEP, ++ .bmc_cmdq_readp = XDMA_AST2500_BMC_CMDQ_READP, ++ .control = XDMA_AST2500_CTRL, ++ .status = XDMA_AST2500_STATUS, + }, -+ { -+ .compatible = "aspeed,ast2700-usb3bhp", ++ .status_bits = { ++ .us_comp = XDMA_AST2500_STATUS_US_COMP, ++ .ds_comp = XDMA_AST2500_STATUS_DS_COMP, ++ .ds_dirty = XDMA_AST2500_STATUS_DS_DIRTY, + }, -+ { -+ .compatible = "aspeed,ast2700-usb2ahp", ++ .set_cmd = aspeed_xdma_ast2500_set_cmd, ++}; ++ ++static const struct aspeed_xdma_chip aspeed_ast2600_xdma_chip = { ++ .control = XDMA_AST2600_CTRL_US_COMP | XDMA_AST2600_CTRL_DS_COMP | ++ XDMA_AST2600_CTRL_DS_DIRTY | XDMA_AST2600_CTRL_DS_SIZE_256, ++ .scu_bmc_class = SCU_AST2600_BMC_CLASS_REV, ++ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL, ++ .scu_misc_mask = SCU_AST2600_MISC_CTRL_XDMA_BMC, ++ .scu_disable_mask = DEBUG_CTRL_AST2600_XDMA_DISABLE, ++ .scu_pcie_conf = SCU_AST2600_PCIE_CONF, ++ .scu_pcie_ctrl = 0, ++ .queue_entry_size = XDMA_AST2600_QUEUE_ENTRY_SIZE, ++ .regs = { ++ .bmc_cmdq_addr = XDMA_AST2600_BMC_CMDQ_ADDR, ++ .bmc_cmdq_addr_ext = 0, ++ .bmc_cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP, ++ .bmc_cmdq_writep = XDMA_AST2600_BMC_CMDQ_WRITEP, ++ .bmc_cmdq_readp = XDMA_AST2600_BMC_CMDQ_READP, ++ .control = XDMA_AST2600_CTRL, ++ .status = XDMA_AST2600_STATUS, + }, -+ { -+ .compatible = "aspeed,ast2700-usb2bhp", ++ .status_bits = { ++ .us_comp = XDMA_AST2600_STATUS_US_COMP, ++ .ds_comp = XDMA_AST2600_STATUS_DS_COMP, ++ .ds_dirty = XDMA_AST2600_STATUS_DS_DIRTY, + }, -+ {} ++ .set_cmd = aspeed_xdma_ast2600_set_cmd, +}; -+MODULE_DEVICE_TABLE(of, aspeed_usb_hp_dt_ids); -+ -+static int aspeed_usb_hp_probe(struct platform_device *pdev) -+{ -+ struct device_node *node = pdev->dev.of_node; -+ void __iomem *regs; -+ bool ehci_32bits_quirk; -+ u32 val; -+ struct clk *clk; -+ struct reset_control *rst; -+ struct regmap *device; -+ struct phy *usb3_phy; -+ bool is_pcie_xhci; -+ int rc = 0; -+ -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2600-usb2ahp")) { -+ dev_info(&pdev->dev, "Initialized AST2600 USB2AHP\n"); -+ return 0; -+ } -+ -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2700-usb3ahp") || -+ of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2700-usb3bhp")) { -+ is_pcie_xhci = true; -+ } else if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2700-usb2ahp") || -+ of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2700-usb2bhp")) { -+ is_pcie_xhci = false; -+ } -+ clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ -+ rc = clk_prepare_enable(clk); -+ if (rc) { -+ dev_err(&pdev->dev, "Unable to enable clock (%d)\n", rc); -+ return rc; -+ } -+ -+ rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); -+ if (IS_ERR(rst)) { -+ rc = PTR_ERR(rst); -+ goto err; -+ } -+ rc = reset_control_deassert(rst); -+ if (rc) -+ goto err; -+ -+ device = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "aspeed,device"); -+ if (IS_ERR(device)) { -+ dev_err(&pdev->dev, "failed to find device regmap\n"); -+ goto err; -+ } -+ -+ if (is_pcie_xhci) { -+ usb3_phy = devm_phy_get(&pdev->dev, "usb3-phy"); -+ if (IS_ERR(usb3_phy)) { -+ rc = dev_err_probe(&pdev->dev, PTR_ERR(usb3_phy), -+ "failed to get usb3 phy\n"); -+ goto err; -+ } -+ rc = phy_init(usb3_phy); -+ if (rc < 0) { -+ dev_err(&pdev->dev, "failed to init usb3 phy\n"); -+ goto err; -+ } -+ //EnPCIaMSI_EnPCIaIntA_EnPCIaMst_EnPCIaDev -+ /* Turn on PCIe xHCI without MSI */ -+ regmap_update_bits(device, 0x70, -+ BIT(19) | BIT(11) | BIT(3), -+ BIT(19) | BIT(11) | BIT(3)); -+ } else { -+ ehci_32bits_quirk = -+ device_property_read_bool(&pdev->dev, "aspeed,ehci_32bits_quirk"); + -+ if (ehci_32bits_quirk) { -+ regs = of_iomap(node, 0); -+ val = readl(regs + USB_HP_BEHCI84) & ~BIT(11); -+ writel(val, regs + USB_HP_BEHCI84); -+ } ++static const struct aspeed_xdma_chip aspeed_ast2700_xdma0_chip = { ++ .control = XDMA_AST2700_CTRL_US_COMP | XDMA_AST2700_CTRL_DS_COMP | ++ XDMA_AST2700_CTRL_DS_DIRTY, ++ .scu_bmc_class = SCU_AST2700_PCIE0_BMC_CLASS_REV, ++ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL, ++ .scu_misc_mask = SCU_AST2700_MISC_CTRL_XDMA_CLIENT, ++ .scu_disable_mask = DEBUG_CTRL_AST2600_XDMA_DISABLE | DEBUG_CTRL_AST2700_XDMA_DISABLE, ++ .scu_pcie_conf = SCU_AST2700_PCIE0_CONF, ++ .scu_pcie_ctrl = SCU_AST2700_PCIE0_CTRL, ++ .queue_entry_size = XDMA_AST2700_QUEUE_ENTRY_SIZE, ++ .regs = { ++ .bmc_cmdq_addr = XDMA_AST2700_BMC_CMDQ_ADDR0, ++ .bmc_cmdq_addr_ext = XDMA_AST2700_BMC_CMDQ_ADDR1, ++ .bmc_cmdq_endp = XDMA_AST2700_BMC_CMDQ_ENDP, ++ .bmc_cmdq_writep = XDMA_AST2700_BMC_CMDQ_WRITEP, ++ .bmc_cmdq_readp = XDMA_AST2700_BMC_CMDQ_READP, ++ .control = XDMA_AST2700_CTRL, ++ .status = XDMA_AST2700_STATUS, ++ }, ++ .status_bits = { ++ .us_comp = XDMA_AST2700_STATUS_US_COMP, ++ .ds_comp = XDMA_AST2700_STATUS_DS_COMP, ++ .ds_dirty = XDMA_AST2700_STATUS_DS_DIRTY, ++ }, ++ .set_cmd = aspeed_xdma_ast2700_set_cmd, ++}; + -+ //EnPCIaMSI_EnPCIaIntA_EnPCIaMst_EnPCIaDev -+ /* Turn on PCIe EHCI without MSI */ -+ regmap_update_bits(device, 0x70, -+ BIT(18) | BIT(10) | BIT(2), -+ BIT(18) | BIT(10) | BIT(2)); -+ } -+ dev_info(&pdev->dev, "Initialized AST2700 USB Host PCIe\n"); -+ return 0; -+err: -+ if (clk) -+ clk_disable_unprepare(clk); -+ return rc; -+} ++static const struct aspeed_xdma_chip aspeed_ast2700_xdma1_chip = { ++ .control = XDMA_AST2700_CTRL_US_COMP | XDMA_AST2700_CTRL_DS_COMP | ++ XDMA_AST2700_CTRL_DS_DIRTY, ++ .scu_bmc_class = SCU_AST2700_PCIE1_BMC_CLASS_REV, ++ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL, ++ .scu_misc_mask = SCU_AST2700_MISC_CTRL_XDMA_CLIENT, ++ .scu_disable_mask = DEBUG_CTRL_AST2600_XDMA_DISABLE | DEBUG_CTRL_AST2700_XDMA_DISABLE, ++ .scu_pcie_conf = SCU_AST2700_PCIE1_CONF, ++ .scu_pcie_ctrl = SCU_AST2700_PCIE1_CTRL, ++ .queue_entry_size = XDMA_AST2700_QUEUE_ENTRY_SIZE, ++ .regs = { ++ .bmc_cmdq_addr = XDMA_AST2700_BMC_CMDQ_ADDR0, ++ .bmc_cmdq_addr_ext = XDMA_AST2700_BMC_CMDQ_ADDR1, ++ .bmc_cmdq_endp = XDMA_AST2700_BMC_CMDQ_ENDP, ++ .bmc_cmdq_writep = XDMA_AST2700_BMC_CMDQ_WRITEP, ++ .bmc_cmdq_readp = XDMA_AST2700_BMC_CMDQ_READP, ++ .control = XDMA_AST2700_CTRL, ++ .status = XDMA_AST2700_STATUS, ++ }, ++ .status_bits = { ++ .us_comp = XDMA_AST2700_STATUS_US_COMP, ++ .ds_comp = XDMA_AST2700_STATUS_DS_COMP, ++ .ds_dirty = XDMA_AST2700_STATUS_DS_DIRTY, ++ }, ++ .set_cmd = aspeed_xdma_ast2700_set_cmd, ++}; + -+static void aspeed_usb_hp_remove(struct platform_device *pdev) -+{ -+ dev_info(&pdev->dev, "Remove USB Host PCIe\n"); -+} ++static const struct of_device_id aspeed_xdma_match[] = { ++ { ++ .compatible = "aspeed,ast2500-xdma", ++ .data = &aspeed_ast2500_xdma_chip, ++ }, ++ { ++ .compatible = "aspeed,ast2600-xdma", ++ .data = &aspeed_ast2600_xdma_chip, ++ }, ++ { ++ .compatible = "aspeed,ast2700-xdma0", ++ .data = &aspeed_ast2700_xdma0_chip, ++ }, ++ { ++ .compatible = "aspeed,ast2700-xdma1", ++ .data = &aspeed_ast2700_xdma1_chip, ++ }, ++ { }, ++}; + -+static struct platform_driver aspeed_usb_hp_driver = { -+ .probe = aspeed_usb_hp_probe, -+ .remove = aspeed_usb_hp_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_usb_hp_dt_ids, ++static struct platform_driver aspeed_xdma_driver = { ++ .probe = aspeed_xdma_probe, ++ .remove = aspeed_xdma_remove, ++ .driver = { ++ .name = DEVICE_NAME, ++ .of_match_table = aspeed_xdma_match, + }, +}; -+module_platform_driver(aspeed_usb_hp_driver); + ++module_platform_driver(aspeed_xdma_driver); ++ ++MODULE_AUTHOR("Eddie James"); ++MODULE_DESCRIPTION("ASPEED XDMA Engine Driver"); +MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Neal Liu "); -diff --git a/drivers/soc/aspeed/aspeed-usb-phy.c b/drivers/soc/aspeed/aspeed-usb-phy.c ---- a/drivers/soc/aspeed/aspeed-usb-phy.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-usb-phy.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,112 @@ -+// SPDX-License-Identifier: GPL-2.0+ +diff --git a/drivers/soc/aspeed/ast2600-otp.c b/drivers/soc/aspeed/ast2600-otp.c +--- a/drivers/soc/aspeed/ast2600-otp.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/ast2600-otp.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,638 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright 2021 Aspeed Technology Inc. ++ * Copyright (C) ASPEED Technology Inc. + */ + -+#include -+#include ++#include ++#include ++#include ++#include +#include -+#include -+#include +#include ++#include ++#include +#include ++#include ++#include +#include ++#include ++#include + -+struct usb_phy_ctrl { -+ u32 offset; -+ u32 value; -+}; -+ -+static const struct of_device_id aspeed_usb_phy_dt_ids[] = { -+ { -+ .compatible = "aspeed,ast2600-uphyb", -+ }, -+ { -+ .compatible = "aspeed,ast2700-uphy2a", -+ }, -+ { -+ .compatible = "aspeed,ast2700-uphy2b", -+ }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_usb_phy_dt_ids); -+ -+static int aspeed_usb_phy_probe(struct platform_device *pdev) -+{ -+ struct device_node *node = pdev->dev.of_node; -+ struct usb_phy_ctrl *ctrl_data; -+ void __iomem *base; -+ struct regmap *scu; -+ int ctrl_num = 1; -+ int ret, i; -+ u32 val; ++#define ASPEED_REVISION_ID0 0x04 ++#define ASPEED_REVISION_ID1 0x14 ++#define ID0_AST2600A0 0x05000303 ++#define ID1_AST2600A0 0x05000303 ++#define ID0_AST2600A1 0x05010303 ++#define ID1_AST2600A1 0x05010303 ++#define ID0_AST2600A2 0x05010303 ++#define ID1_AST2600A2 0x05020303 ++#define ID0_AST2600A3 0x05030303 ++#define ID1_AST2600A3 0x05030303 ++#define ID0_AST2620A1 0x05010203 ++#define ID1_AST2620A1 0x05010203 ++#define ID0_AST2620A2 0x05010203 ++#define ID1_AST2620A2 0x05020203 ++#define ID0_AST2620A3 0x05030203 ++#define ID1_AST2620A3 0x05030203 ++#define ID0_AST2605A2 0x05010103 ++#define ID1_AST2605A2 0x05020103 ++#define ID0_AST2605A3 0x05030103 ++#define ID1_AST2605A3 0x05030103 ++#define ID0_AST2625A3 0x05030403 ++#define ID1_AST2625A3 0x05030403 + -+ scu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "aspeed,scu"); -+ if (IS_ERR(scu)) { -+ dev_err(&pdev->dev, "cannot to find SCU regmap\n"); -+ return -ENODEV; -+ } ++#define OTP_PROTECT_KEY 0x0 ++#define OTP_PASSWD 0x349fe38a ++#define OTP_COMMAND 0x4 ++#define OTP_TIMING 0x8 ++#define OTP_ADDR 0x10 ++#define OTP_STATUS 0x14 ++#define OTP_COMPARE_1 0x20 ++#define OTP_COMPARE_2 0x24 ++#define OTP_COMPARE_3 0x28 ++#define OTP_COMPARE_4 0x2c ++#define SW_REV_ID0 0x68 ++#define SW_REV_ID1 0x6c ++#define SEC_KEY_NUM 0x78 ++#define RETRY 20 + -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2600-uphyb")) { -+ /* Check SCU040[3] USB port B controller reset is deassert */ -+ regmap_read(scu, 0x40, &val); -+ if ((val & BIT(3))) -+ return -EPROBE_DEFER; -+ } ++struct aspeed_otp { ++ struct miscdevice miscdev; ++ void __iomem *reg_base; ++ bool is_open; ++ u32 otp_ver; ++ u32 *data; ++}; + -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2700-uphy2a")) { -+ /* Check SCU220[0] USB vHubA1 controller reset is deassert */ -+ regmap_read(scu, 0x220, &val); -+ if ((val & BIT(0))) -+ return -EPROBE_DEFER; -+ } ++static DEFINE_SPINLOCK(otp_state_lock); + -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2700-uphy2b")) { -+ /* Check SCU220[3] USB vHubB1 controller reset is deassert */ -+ regmap_read(scu, 0x220, &val); -+ if ((val & BIT(3))) -+ return -EPROBE_DEFER; -+ } ++static inline u32 aspeed_otp_read(struct aspeed_otp *ctx, u32 reg) ++{ ++ int val; + -+ ctrl_data = devm_kzalloc(&pdev->dev, -+ sizeof(struct usb_phy_ctrl) * ctrl_num, -+ GFP_KERNEL); -+ if (!ctrl_data) -+ return -ENOMEM; ++ val = readl(ctx->reg_base + reg); ++ // printk("read:reg = 0x%08x, val = 0x%08x\n", reg, val); ++ return val; ++} + -+ base = of_iomap(node, 0); ++static inline void aspeed_otp_write(struct aspeed_otp *ctx, u32 val, u32 reg) ++{ ++ // printk("write:reg = 0x%08x, val = 0x%08x\n", reg, val); ++ writel(val, ctx->reg_base + reg); ++} + -+ ret = of_property_read_u32_array(node, "ctrl", (u32 *)ctrl_data, -+ ctrl_num * 2); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "Could not read ctrl property\n"); -+ return -EINVAL; ++static uint32_t chip_version(u32 revid0, u32 revid1) ++{ ++ if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { ++ /* AST2600-A0 */ ++ return OTP_A0; ++ } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { ++ /* AST2600-A1 */ ++ return OTP_A1; ++ } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { ++ /* AST2600-A2 */ ++ return OTP_A2; ++ } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { ++ /* AST2600-A3 */ ++ return OTP_A3; ++ } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { ++ /* AST2620-A1 */ ++ return OTP_A1; ++ } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { ++ /* AST2620-A2 */ ++ return OTP_A2; ++ } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { ++ /* AST2620-A3 */ ++ return OTP_A3; ++ } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { ++ /* AST2605-A2 */ ++ return OTP_A2; ++ } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { ++ /* AST2605-A3 */ ++ return OTP_A3; ++ } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { ++ /* AST2605-A3 */ ++ return OTP_A3; + } ++ return -1; ++} + -+ for (i = 0; i < ctrl_num; i++) -+ writel(ctrl_data[i].value, base + ctrl_data[i].offset); -+ -+ dev_info(&pdev->dev, "Initialized USB PHY\n"); ++static void wait_complete(struct aspeed_otp *ctx) ++{ ++ int reg; ++ int i = 0; + -+ return 0; ++ do { ++ reg = aspeed_otp_read(ctx, OTP_STATUS); ++ if ((reg & 0x6) == 0x6) ++ i++; ++ } while (i != 2); +} + -+static void aspeed_usb_phy_remove(struct platform_device *pdev) ++static void otp_write(struct aspeed_otp *ctx, u32 otp_addr, u32 val) +{ ++ aspeed_otp_write(ctx, otp_addr, OTP_ADDR); //write address ++ aspeed_otp_write(ctx, val, OTP_COMPARE_1); //write val ++ aspeed_otp_write(ctx, 0x23b1e362, OTP_COMMAND); //write command ++ wait_complete(ctx); +} + -+static struct platform_driver aspeed_usb_phy_driver = { -+ .probe = aspeed_usb_phy_probe, -+ .remove = aspeed_usb_phy_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_usb_phy_dt_ids, -+ }, -+}; -+module_platform_driver(aspeed_usb_phy_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Neal Liu "); -diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c ---- a/drivers/soc/aspeed/aspeed-xdma.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-xdma.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,1438 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright IBM Corp 2019 ++static void otp_soak(struct aspeed_otp *ctx, int soak) ++{ ++ if (ctx->otp_ver == OTP_A2 || ctx->otp_ver == OTP_A3) { ++ switch (soak) { ++ case 0: //default ++ otp_write(ctx, 0x3000, 0x0); // Write MRA ++ otp_write(ctx, 0x5000, 0x0); // Write MRB ++ otp_write(ctx, 0x1000, 0x0); // Write MR ++ break; ++ case 1: //normal program ++ otp_write(ctx, 0x3000, 0x1320); // Write MRA ++ otp_write(ctx, 0x5000, 0x1008); // Write MRB ++ otp_write(ctx, 0x1000, 0x0024); // Write MR ++ aspeed_otp_write(ctx, 0x04191388, OTP_TIMING); // 200us ++ break; ++ case 2: //soak program ++ otp_write(ctx, 0x3000, 0x1320); // Write MRA ++ otp_write(ctx, 0x5000, 0x0007); // Write MRB ++ otp_write(ctx, 0x1000, 0x0100); // Write MR ++ aspeed_otp_write(ctx, 0x04193a98, OTP_TIMING); // 600us ++ break; ++ } ++ } else { ++ switch (soak) { ++ case 0: //default ++ otp_write(ctx, 0x3000, 0x0); // Write MRA ++ otp_write(ctx, 0x5000, 0x0); // Write MRB ++ otp_write(ctx, 0x1000, 0x0); // Write MR ++ break; ++ case 1: //normal program ++ otp_write(ctx, 0x3000, 0x4021); // Write MRA ++ otp_write(ctx, 0x5000, 0x302f); // Write MRB ++ otp_write(ctx, 0x1000, 0x4020); // Write MR ++ aspeed_otp_write(ctx, 0x04190760, OTP_TIMING); // 75us ++ break; ++ case 2: //soak program ++ otp_write(ctx, 0x3000, 0x4021); // Write MRA ++ otp_write(ctx, 0x5000, 0x1027); // Write MRB ++ otp_write(ctx, 0x1000, 0x4820); // Write MR ++ aspeed_otp_write(ctx, 0x041930d4, OTP_TIMING); // 500us ++ break; ++ } ++ } + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ wait_complete(ctx); ++} + -+#define DEVICE_NAME "aspeed-xdma" ++static int verify_bit(struct aspeed_otp *ctx, u32 otp_addr, int bit_offset, int value) ++{ ++ u32 ret[2]; + -+#define SCU_AST2600_MISC_CTRL 0x0c0 -+#define SCU_AST2600_MISC_CTRL_XDMA_BMC BIT(8) -+#define SCU_AST2700_MISC_CTRL_XDMA_CLIENT BIT(4) ++ if (otp_addr % 2 == 0) ++ aspeed_otp_write(ctx, otp_addr, OTP_ADDR); //Read address ++ else ++ aspeed_otp_write(ctx, otp_addr - 1, OTP_ADDR); //Read address + -+#define SCU_AST2600_DEBUG_CTRL 0x0c8 -+#define DEBUG_CTRL_AST2600_XDMA_DISABLE BIT(2) -+#define DEBUG_CTRL_AST2700_XDMA_DISABLE BIT(8) ++ aspeed_otp_write(ctx, 0x23b1e361, OTP_COMMAND); //trigger read ++ wait_complete(ctx); ++ ret[0] = aspeed_otp_read(ctx, OTP_COMPARE_1); ++ ret[1] = aspeed_otp_read(ctx, OTP_COMPARE_2); + -+#define SCU_AST2500_PCIE_CONF 0x180 -+#define SCU_AST2600_PCIE_CONF 0xc20 -+#define SCU_AST2700_PCIE0_CONF 0x970 -+#define SCU_AST2700_PCIE1_CONF 0x9B0 -+#define SCU_PCIE_CONF_VGA_EN BIT(0) -+#define SCU_PCIE_CONF_VGA_EN_MMIO BIT(1) -+#define SCU_PCIE_CONF_VGA_EN_LPC BIT(2) -+#define SCU_PCIE_CONF_VGA_EN_MSI BIT(3) -+#define SCU_PCIE_CONF_VGA_EN_MCTP BIT(4) -+#define SCU_PCIE_CONF_VGA_EN_IRQ BIT(5) -+#define SCU_PCIE_CONF_VGA_EN_DMA BIT(6) -+#define SCU_PCIE_CONF_BMC_EN BIT(8) -+#define SCU_PCIE_CONF_BMC_EN_MMIO BIT(9) -+#define SCU_PCIE_CONF_BMC_EN_MSI BIT(11) -+#define SCU_PCIE_CONF_BMC_EN_MCTP BIT(12) -+#define SCU_PCIE_CONF_BMC_EN_IRQ BIT(13) -+#define SCU_PCIE_CONF_BMC_EN_DMA BIT(14) ++ if (otp_addr % 2 == 0) { ++ if (((ret[0] >> bit_offset) & 1) == value) ++ return 0; ++ else ++ return -1; ++ } else { ++ if (((ret[1] >> bit_offset) & 1) == value) ++ return 0; ++ else ++ return -1; ++ } ++} + -+#define SCU_AST2700_PCIE0_CTRL 0xa60 -+#define SCU_AST2700_PCIE1_CTRL 0xae0 -+#define SCU_AST2700_PCIE_CTRL_DMA_EN BIT(2) ++static void otp_prog(struct aspeed_otp *ctx, u32 otp_addr, u32 prog_bit) ++{ ++ otp_write(ctx, 0x0, prog_bit); ++ aspeed_otp_write(ctx, otp_addr, OTP_ADDR); //write address ++ aspeed_otp_write(ctx, prog_bit, OTP_COMPARE_1); //write data ++ aspeed_otp_write(ctx, 0x23b1e364, OTP_COMMAND); //write command ++ wait_complete(ctx); ++} + -+#define SCU_AST2500_BMC_CLASS_REV 0x19c -+#define SCU_AST2600_BMC_CLASS_REV 0xc68 -+#define SCU_AST2700_PCIE0_BMC_CLASS_REV 0xa18 -+#define SCU_AST2700_PCIE1_BMC_CLASS_REV 0xa98 -+#define SCU_BMC_CLASS_REV_XDMA 0xff000001 -+#define SCU_BMC_CLASS_REV_MASK 0xffffff00 ++static void _otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) ++{ ++ int prog_bit; + -+#define XDMA_CMDQ_SIZE PAGE_SIZE -+#define XDMA_NUM_CMDS \ -+ (XDMA_CMDQ_SIZE / sizeof(struct aspeed_xdma_cmd)) ++ if (prog_address % 2 == 0) { ++ if (value) ++ prog_bit = ~(0x1 << bit_offset); ++ else ++ return; ++ } else { ++ if (ctx->otp_ver != OTP_A3) ++ prog_address |= 1 << 15; ++ if (!value) ++ prog_bit = 0x1 << bit_offset; ++ else ++ return; ++ } ++ otp_prog(ctx, prog_address, prog_bit); ++} + -+/* Aspeed specification requires 100us after disabling the reset */ -+#define XDMA_ENGINE_SETUP_TIME_MAX_US 1000 -+#define XDMA_ENGINE_SETUP_TIME_MIN_US 100 ++static int otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) ++{ ++ int pass; ++ int i; + -+#define XDMA_CMD_AST2500_PITCH_SHIFT 3 -+#define XDMA_CMD_AST2500_PITCH_BMC GENMASK_ULL(62, 51) -+#define XDMA_CMD_AST2500_PITCH_HOST GENMASK_ULL(46, 35) -+#define XDMA_CMD_AST2500_PITCH_UPSTREAM BIT_ULL(31) -+#define XDMA_CMD_AST2500_PITCH_ADDR GENMASK_ULL(29, 4) -+#define XDMA_CMD_AST2500_PITCH_ID BIT_ULL(0) -+#define XDMA_CMD_AST2500_CMD_IRQ_EN BIT_ULL(31) -+#define XDMA_CMD_AST2500_CMD_LINE_NO GENMASK_ULL(27, 16) -+#define XDMA_CMD_AST2500_CMD_IRQ_BMC BIT_ULL(15) -+#define XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT 4 -+#define XDMA_CMD_AST2500_CMD_LINE_SIZE \ -+ GENMASK_ULL(14, XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT) -+#define XDMA_CMD_AST2500_CMD_ID BIT_ULL(1) ++ otp_soak(ctx, 1); ++ _otp_prog_bit(ctx, value, prog_address, bit_offset); ++ pass = 0; + -+#define XDMA_CMD_AST2600_PITCH_BMC GENMASK_ULL(62, 48) -+#define XDMA_CMD_AST2600_PITCH_HOST GENMASK_ULL(46, 32) -+#define XDMA_CMD_AST2600_PITCH_ADDR GENMASK_ULL(30, 0) -+#define XDMA_CMD_AST2600_CMD_64_EN BIT_ULL(40) -+#define XDMA_CMD_AST2600_CMD_IRQ_BMC BIT_ULL(37) -+#define XDMA_CMD_AST2600_CMD_IRQ_HOST BIT_ULL(36) -+#define XDMA_CMD_AST2600_CMD_UPSTREAM BIT_ULL(32) -+#define XDMA_CMD_AST2600_CMD_LINE_NO GENMASK_ULL(27, 16) -+#define XDMA_CMD_AST2600_CMD_LINE_SIZE GENMASK_ULL(14, 0) -+#define XDMA_CMD_AST2600_CMD_MULTILINE_SIZE GENMASK_ULL(14, 12) ++ for (i = 0; i < RETRY; i++) { ++ if (verify_bit(ctx, prog_address, bit_offset, value) != 0) { ++ otp_soak(ctx, 2); ++ _otp_prog_bit(ctx, value, prog_address, bit_offset); ++ if (verify_bit(ctx, prog_address, bit_offset, value) != 0) { ++ otp_soak(ctx, 1); ++ } else { ++ pass = 1; ++ break; ++ } ++ } else { ++ pass = 1; ++ break; ++ } ++ } ++ otp_soak(ctx, 0); ++ return pass; ++} + -+#define XDMA_CMD_AST2700_PITCH_BMC GENMASK_ULL(62, 48) -+#define XDMA_CMD_AST2700_PITCH_HOST GENMASK_ULL(46, 32) -+#define XDMA_CMD_AST2700_CMD_64_EN BIT_ULL(40) -+#define XDMA_CMD_AST2700_CMD_IRQ_BMC BIT_ULL(37) -+#define XDMA_CMD_AST2700_CMD_UPSTREAM BIT_ULL(32) -+#define XDMA_CMD_AST2700_CMD_LINE_NO GENMASK_ULL(27, 16) -+#define XDMA_CMD_AST2700_CMD_LINE_SIZE GENMASK_ULL(14, 0) -+#define XDMA_CMD_AST2700_CMD_MULTILINE_SIZE GENMASK_ULL(14, 12) -+#define XDMA_CMD_AST2700_BMC_ADDR GENMASK_ULL(34, 0) ++static void otp_read_conf_dw(struct aspeed_otp *ctx, u32 offset, u32 *buf) ++{ ++ u32 config_offset; + -+#define XDMA_AST2500_QUEUE_ENTRY_SIZE 4 -+#define XDMA_AST2500_HOST_CMDQ_ADDR0 0x00 -+#define XDMA_AST2500_HOST_CMDQ_ENDP 0x04 -+#define XDMA_AST2500_HOST_CMDQ_WRITEP 0x08 -+#define XDMA_AST2500_HOST_CMDQ_READP 0x0c -+#define XDMA_AST2500_BMC_CMDQ_ADDR 0x10 -+#define XDMA_AST2500_BMC_CMDQ_ENDP 0x14 -+#define XDMA_AST2500_BMC_CMDQ_WRITEP 0x18 -+#define XDMA_AST2500_BMC_CMDQ_READP 0x1c -+#define XDMA_BMC_CMDQ_READP_RESET 0xee882266 -+#define XDMA_AST2500_CTRL 0x20 -+#define XDMA_AST2500_CTRL_US_COMP BIT(4) -+#define XDMA_AST2500_CTRL_DS_COMP BIT(5) -+#define XDMA_AST2500_CTRL_DS_DIRTY BIT(6) -+#define XDMA_AST2500_CTRL_DS_SIZE_256 BIT(17) -+#define XDMA_AST2500_CTRL_DS_TIMEOUT BIT(28) -+#define XDMA_AST2500_CTRL_DS_CHECK_ID BIT(29) -+#define XDMA_AST2500_STATUS 0x24 -+#define XDMA_AST2500_STATUS_US_COMP BIT(4) -+#define XDMA_AST2500_STATUS_DS_COMP BIT(5) -+#define XDMA_AST2500_STATUS_DS_DIRTY BIT(6) -+#define XDMA_AST2500_INPRG_DS_CMD1 0x38 -+#define XDMA_AST2500_INPRG_DS_CMD2 0x3c -+#define XDMA_AST2500_INPRG_US_CMD00 0x40 -+#define XDMA_AST2500_INPRG_US_CMD01 0x44 -+#define XDMA_AST2500_INPRG_US_CMD10 0x48 -+#define XDMA_AST2500_INPRG_US_CMD11 0x4c -+#define XDMA_AST2500_INPRG_US_CMD20 0x50 -+#define XDMA_AST2500_INPRG_US_CMD21 0x54 -+#define XDMA_AST2500_HOST_CMDQ_ADDR1 0x60 -+#define XDMA_AST2500_VGA_CMDQ_ADDR0 0x64 -+#define XDMA_AST2500_VGA_CMDQ_ENDP 0x68 -+#define XDMA_AST2500_VGA_CMDQ_WRITEP 0x6c -+#define XDMA_AST2500_VGA_CMDQ_READP 0x70 -+#define XDMA_AST2500_VGA_CMD_STATUS 0x74 -+#define XDMA_AST2500_VGA_CMDQ_ADDR1 0x78 ++ config_offset = 0x800; ++ config_offset |= (offset / 8) * 0x200; ++ config_offset |= (offset % 8) * 0x2; + -+#define XDMA_AST2600_QUEUE_ENTRY_SIZE 2 -+#define XDMA_AST2600_HOST_CMDQ_ADDR0 0x00 -+#define XDMA_AST2600_HOST_CMDQ_ADDR1 0x04 -+#define XDMA_AST2600_HOST_CMDQ_ENDP 0x08 -+#define XDMA_AST2600_HOST_CMDQ_WRITEP 0x0c -+#define XDMA_AST2600_HOST_CMDQ_READP 0x10 -+#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14 -+#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18 -+#define XDMA_AST2600_BMC_CMDQ_WRITEP 0x1c -+#define XDMA_AST2600_BMC_CMDQ_READP 0x20 -+#define XDMA_AST2600_VGA_CMDQ_ADDR0 0x24 -+#define XDMA_AST2600_VGA_CMDQ_ADDR1 0x28 -+#define XDMA_AST2600_VGA_CMDQ_ENDP 0x2c -+#define XDMA_AST2600_VGA_CMDQ_WRITEP 0x30 -+#define XDMA_AST2600_VGA_CMDQ_READP 0x34 -+#define XDMA_AST2600_CTRL 0x38 -+#define XDMA_AST2600_CTRL_US_COMP BIT(16) -+#define XDMA_AST2600_CTRL_DS_COMP BIT(17) -+#define XDMA_AST2600_CTRL_DS_DIRTY BIT(18) -+#define XDMA_AST2600_CTRL_DS_SIZE_256 BIT(20) -+#define XDMA_AST2600_STATUS 0x3c -+#define XDMA_AST2600_STATUS_US_COMP BIT(16) -+#define XDMA_AST2600_STATUS_DS_COMP BIT(17) -+#define XDMA_AST2600_STATUS_DS_DIRTY BIT(18) -+#define XDMA_AST2600_INPRG_DS_CMD00 0x40 -+#define XDMA_AST2600_INPRG_DS_CMD01 0x44 -+#define XDMA_AST2600_INPRG_DS_CMD10 0x48 -+#define XDMA_AST2600_INPRG_DS_CMD11 0x4c -+#define XDMA_AST2600_INPRG_DS_CMD20 0x50 -+#define XDMA_AST2600_INPRG_DS_CMD21 0x54 -+#define XDMA_AST2600_INPRG_US_CMD00 0x60 -+#define XDMA_AST2600_INPRG_US_CMD01 0x64 -+#define XDMA_AST2600_INPRG_US_CMD10 0x68 -+#define XDMA_AST2600_INPRG_US_CMD11 0x6c -+#define XDMA_AST2600_INPRG_US_CMD20 0x70 -+#define XDMA_AST2600_INPRG_US_CMD21 0x74 ++ aspeed_otp_write(ctx, config_offset, OTP_ADDR); //Read address ++ aspeed_otp_write(ctx, 0x23b1e361, OTP_COMMAND); //trigger read ++ wait_complete(ctx); ++ buf[0] = aspeed_otp_read(ctx, OTP_COMPARE_1); ++} + -+#define XDMA_AST2700_QUEUE_ENTRY_SIZE 2 -+#define XDMA_AST2700_BMC_CMDQ_ADDR0 0x10 -+#define XDMA_AST2700_BMC_CMDQ_ADDR1 0x14 -+#define XDMA_AST2700_BMC_CMDQ_ENDP 0x18 -+#define XDMA_AST2700_BMC_CMDQ_WRITEP 0x1c -+#define XDMA_AST2700_BMC_CMDQ_READP 0x20 -+#define XDMA_AST2700_CTRL 0x38 -+#define XDMA_AST2700_CTRL_US_COMP BIT(16) -+#define XDMA_AST2700_CTRL_DS_COMP BIT(17) -+#define XDMA_AST2700_CTRL_DS_DIRTY BIT(18) -+#define XDMA_AST2700_CTRL_IDLE BIT(19) -+#define XDMA_AST2700_CTRL_DS_SIZE_256 BIT(20) -+#define XDMA_AST2700_STATUS 0x3c -+#define XDMA_AST2700_STATUS_US_COMP BIT(16) -+#define XDMA_AST2700_STATUS_DS_COMP BIT(17) -+#define XDMA_AST2700_STATUS_DS_DIRTY BIT(18) -+#define XDMA_AST2700_STATUS_IDLE BIT(19) -+#define XDMA_AST2700_INPRG_DS_CMD00 0x40 -+#define XDMA_AST2700_INPRG_DS_CMD01 0x44 -+#define XDMA_AST2700_INPRG_DS_CMD10 0x48 -+#define XDMA_AST2700_INPRG_DS_CMD11 0x4c -+#define XDMA_AST2700_INPRG_DS_CMD20 0x50 -+#define XDMA_AST2700_INPRG_DS_CMD21 0x54 -+#define XDMA_AST2700_INPRG_US_CMD00 0x60 -+#define XDMA_AST2700_INPRG_US_CMD01 0x64 -+#define XDMA_AST2700_INPRG_US_CMD10 0x68 -+#define XDMA_AST2700_INPRG_US_CMD11 0x6c -+#define XDMA_AST2700_INPRG_US_CMD20 0x70 -+#define XDMA_AST2700_INPRG_US_CMD21 0x74 ++static void otp_read_conf(struct aspeed_otp *ctx, u32 offset, u32 len) ++{ ++ int i, j; + -+struct aspeed_xdma_cmd { -+ u64 host_addr; -+ u64 pitch; -+ u64 cmd; -+ u64 reserved; -+}; ++ otp_soak(ctx, 0); ++ for (i = offset, j = 0; j < len; i++, j++) ++ otp_read_conf_dw(ctx, i, &ctx->data[j]); ++} + -+struct aspeed_xdma_regs { -+ u8 bmc_cmdq_addr; -+ u8 bmc_cmdq_addr_ext; -+ u8 bmc_cmdq_endp; -+ u8 bmc_cmdq_writep; -+ u8 bmc_cmdq_readp; -+ u8 control; -+ u8 status; -+}; ++static void otp_read_data_2dw(struct aspeed_otp *ctx, u32 offset, u32 *buf) ++{ ++ aspeed_otp_write(ctx, offset, OTP_ADDR); //Read address ++ aspeed_otp_write(ctx, 0x23b1e361, OTP_COMMAND); //trigger read ++ wait_complete(ctx); ++ buf[0] = aspeed_otp_read(ctx, OTP_COMPARE_1); ++ buf[1] = aspeed_otp_read(ctx, OTP_COMPARE_2); ++} + -+struct aspeed_xdma_status_bits { -+ u32 us_comp; -+ u32 ds_comp; -+ u32 ds_dirty; -+}; ++static void otp_read_data(struct aspeed_otp *ctx, u32 offset, u32 len) ++{ ++ int i, j; ++ u32 ret[2]; + -+struct aspeed_xdma; ++ otp_soak(ctx, 0); + -+struct aspeed_xdma_chip { -+ u32 control; -+ u32 scu_bmc_class; -+ u32 scu_misc_ctrl; -+ u32 scu_misc_mask; -+ u32 scu_disable_mask; -+ u32 scu_pcie_conf; -+ u32 scu_pcie_ctrl; -+ unsigned int queue_entry_size; -+ struct aspeed_xdma_regs regs; -+ struct aspeed_xdma_status_bits status_bits; -+ unsigned int (*set_cmd)(struct aspeed_xdma *ctx, -+ struct aspeed_xdma_cmd cmds[2], -+ struct aspeed_xdma_op *op, u64 bmc_addr); -+}; ++ i = offset; ++ j = 0; ++ if (offset % 2) { ++ otp_read_data_2dw(ctx, i - 1, ret); ++ ctx->data[0] = ret[1]; ++ i++; ++ j++; ++ } ++ for (; j < len; i += 2, j += 2) ++ otp_read_data_2dw(ctx, i, &ctx->data[j]); ++} + -+struct aspeed_xdma_client; ++static int otp_prog_data(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) ++{ ++ u32 read[2]; ++ int otp_bit; + -+struct aspeed_xdma { -+ struct kobject kobj; -+ const struct aspeed_xdma_chip *chip; ++ if (dw_offset % 2 == 0) { ++ otp_read_data_2dw(ctx, dw_offset, read); ++ otp_bit = (read[0] >> bit_offset) & 0x1; + -+ int irq; -+ int pcie_irq; -+ struct clk *clock; -+ struct device *dev; -+ void __iomem *base; -+ resource_size_t res_size; -+ resource_size_t res_start; -+ struct reset_control *reset; -+ struct reset_control *reset_rc; ++ if (otp_bit == 1 && value == 0) { ++ pr_err("OTPDATA%X[%X] = 1\n", dw_offset, bit_offset); ++ pr_err("OTP is programed, which can't be cleaned\n"); ++ return -EINVAL; ++ } ++ } else { ++ otp_read_data_2dw(ctx, dw_offset - 1, read); ++ otp_bit = (read[1] >> bit_offset) & 0x1; + -+ /* Protects current_client */ -+ spinlock_t client_lock; -+ struct aspeed_xdma_client *current_client; ++ if (otp_bit == 0 && value == 1) { ++ pr_err("OTPDATA%X[%X] = 1\n", dw_offset, bit_offset); ++ pr_err("OTP is programed, which can't be writen\n"); ++ return -EINVAL; ++ } ++ } ++ if (otp_bit == value) { ++ pr_err("OTPDATA%X[%X] = %d\n", dw_offset, bit_offset, value); ++ pr_err("No need to program\n"); ++ return 0; ++ } + -+ /* Protects engine configuration */ -+ spinlock_t engine_lock; -+ struct aspeed_xdma_cmd *cmdq; -+ unsigned int cmd_idx; -+ bool in_reset; -+ bool upstream; ++ return otp_prog_bit(ctx, value, dw_offset, bit_offset); ++} + -+ /* Queue waiters for idle engine */ -+ wait_queue_head_t wait; ++static int otp_prog_conf(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) ++{ ++ u32 read; ++ u32 prog_address = 0; ++ int otp_bit; + -+ struct work_struct reset_work; ++ otp_read_conf_dw(ctx, dw_offset, &read); + -+ phys_addr_t mem_phys; -+ phys_addr_t mem_size; -+ void *mem_virt; -+ dma_addr_t mem_coherent; -+ dma_addr_t cmdq_phys; -+ struct gen_pool *pool; ++ prog_address = 0x800; ++ prog_address |= (dw_offset / 8) * 0x200; ++ prog_address |= (dw_offset % 8) * 0x2; ++ otp_bit = (read >> bit_offset) & 0x1; ++ if (otp_bit == value) { ++ pr_err("OTPCFG%X[%X] = %d\n", dw_offset, bit_offset, value); ++ pr_err("No need to program\n"); ++ return 0; ++ } ++ if (otp_bit == 1 && value == 0) { ++ pr_err("OTPCFG%X[%X] = 1\n", dw_offset, bit_offset); ++ pr_err("OTP is programed, which can't be clean\n"); ++ return -EINVAL; ++ } + -+ struct miscdevice misc; -+}; ++ return otp_prog_bit(ctx, value, prog_address, bit_offset); ++} + -+struct aspeed_xdma_client { -+ struct aspeed_xdma *ctx; ++struct aspeed_otp *glob_ctx; + -+ bool error; -+ bool in_progress; -+ void *virt; -+ dma_addr_t phys; -+ u32 size; -+}; ++void otp_read_data_buf(u32 offset, u32 *buf, u32 len) ++{ ++ int i, j; ++ u32 ret[2]; + -+#define CREATE_TRACE_POINTS -+#include ++ aspeed_otp_write(glob_ctx, OTP_PASSWD, OTP_PROTECT_KEY); + -+static u32 aspeed_xdma_readl(struct aspeed_xdma *ctx, u8 reg) ++ otp_soak(glob_ctx, 0); ++ ++ i = offset; ++ j = 0; ++ if (offset % 2) { ++ otp_read_data_2dw(glob_ctx, i - 1, ret); ++ buf[0] = ret[1]; ++ i++; ++ j++; ++ } ++ for (; j < len; i += 2, j += 2) ++ otp_read_data_2dw(glob_ctx, i, &buf[j]); ++ aspeed_otp_write(glob_ctx, 0, OTP_PROTECT_KEY); ++} ++EXPORT_SYMBOL(otp_read_data_buf); ++ ++void otp_read_conf_buf(u32 offset, u32 *buf, u32 len) +{ -+ u32 v = readl(ctx->base + reg); ++ int i, j; + -+ dev_dbg(ctx->dev, "read %02x[%08x]\n", reg, v); -+ return v; ++ aspeed_otp_write(glob_ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++ otp_soak(glob_ctx, 0); ++ for (i = offset, j = 0; j < len; i++, j++) ++ otp_read_conf_dw(glob_ctx, i, &buf[j]); ++ aspeed_otp_write(glob_ctx, 0, OTP_PROTECT_KEY); +} ++EXPORT_SYMBOL(otp_read_conf_buf); + -+static void aspeed_xdma_writel(struct aspeed_xdma *ctx, u8 reg, u32 val) ++static long otp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ -+ writel(val, ctx->base + reg); -+ dev_dbg(ctx->dev, "write %02x[%08x]\n", reg, val); ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++ void __user *argp = (void __user *)arg; ++ struct otp_read xfer; ++ struct otp_prog prog; ++ u32 reg_read[2]; ++ int ret = 0; ++ ++ switch (cmd) { ++ case ASPEED_OTP_READ_DATA: ++ if (copy_from_user(&xfer, argp, sizeof(struct otp_read))) ++ return -EFAULT; ++ if ((xfer.offset + xfer.len) > 0x800) { ++ pr_err("out of range"); ++ return -EINVAL; ++ } ++ ++ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++ otp_read_data(ctx, xfer.offset, xfer.len); ++ aspeed_otp_write(ctx, 0, OTP_PROTECT_KEY); ++ ++ if (copy_to_user(xfer.data, ctx->data, xfer.len * 4)) ++ return -EFAULT; ++ if (copy_to_user(argp, &xfer, sizeof(struct otp_read))) ++ return -EFAULT; ++ break; ++ case ASPEED_OTP_READ_CONF: ++ if (copy_from_user(&xfer, argp, sizeof(struct otp_read))) ++ return -EFAULT; ++ if ((xfer.offset + xfer.len) > 0x800) { ++ pr_err("out of range"); ++ return -EINVAL; ++ } ++ ++ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++ otp_read_conf(ctx, xfer.offset, xfer.len); ++ aspeed_otp_write(ctx, 0, OTP_PROTECT_KEY); ++ ++ if (copy_to_user(xfer.data, ctx->data, xfer.len * 4)) ++ return -EFAULT; ++ if (copy_to_user(argp, &xfer, sizeof(struct otp_read))) ++ return -EFAULT; ++ break; ++ case ASPEED_OTP_PROG_DATA: ++ if (copy_from_user(&prog, argp, sizeof(struct otp_prog))) ++ return -EFAULT; ++ if (prog.bit_offset >= 32 || (prog.value != 0 && prog.value != 1)) { ++ pr_err("out of range"); ++ return -EINVAL; ++ } ++ if (prog.dw_offset >= 0x800) { ++ pr_err("out of range"); ++ return -EINVAL; ++ } ++ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++ ret = otp_prog_data(ctx, prog.value, prog.dw_offset, prog.bit_offset); ++ break; ++ case ASPEED_OTP_PROG_CONF: ++ if (copy_from_user(&prog, argp, sizeof(struct otp_prog))) ++ return -EFAULT; ++ if (prog.bit_offset >= 32 || (prog.value != 0 && prog.value != 1)) { ++ pr_err("out of range"); ++ return -EINVAL; ++ } ++ if (prog.dw_offset >= 0x20) { ++ pr_err("out of range"); ++ return -EINVAL; ++ } ++ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++ ret = otp_prog_conf(ctx, prog.value, prog.dw_offset, prog.bit_offset); ++ break; ++ case ASPEED_OTP_VER: ++ if (copy_to_user(argp, &ctx->otp_ver, sizeof(u32))) ++ return -EFAULT; ++ break; ++ case ASPEED_OTP_SW_RID: ++ reg_read[0] = aspeed_otp_read(ctx, SW_REV_ID0); ++ reg_read[1] = aspeed_otp_read(ctx, SW_REV_ID1); ++ if (copy_to_user(argp, reg_read, sizeof(u32) * 2)) ++ return -EFAULT; ++ break; ++ case ASPEED_SEC_KEY_NUM: ++ reg_read[0] = aspeed_otp_read(ctx, SEC_KEY_NUM) & 7; ++ if (copy_to_user(argp, reg_read, sizeof(u32))) ++ return -EFAULT; ++ break; ++ } ++ return ret; +} + -+static void aspeed_xdma_init_eng(struct aspeed_xdma *ctx) ++static int otp_open(struct inode *inode, struct file *file) +{ -+ unsigned long flags; ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ spin_lock_irqsave(&ctx->engine_lock, flags); -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_endp, -+ ctx->chip->queue_entry_size * XDMA_NUM_CMDS); -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_readp, -+ XDMA_BMC_CMDQ_READP_RESET); -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, 0); -+ aspeed_xdma_writel(ctx, ctx->chip->regs.control, ctx->chip->control); -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_addr, ctx->cmdq_phys); -+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -+ if (ctx->chip->regs.bmc_cmdq_addr_ext) -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_addr_ext, ctx->cmdq_phys >> 32); -+#endif ++ spin_lock(&otp_state_lock); + -+ ctx->cmd_idx = 0; -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ if (ctx->is_open) { ++ spin_unlock(&otp_state_lock); ++ return -EBUSY; ++ } ++ ++ ctx->is_open = true; ++ ++ spin_unlock(&otp_state_lock); ++ ++ return 0; +} + -+static unsigned int aspeed_xdma_ast2500_set_cmd(struct aspeed_xdma *ctx, -+ struct aspeed_xdma_cmd cmds[2], -+ struct aspeed_xdma_op *op, -+ u64 bmc_addr) ++static int otp_release(struct inode *inode, struct file *file) +{ -+ unsigned int rc = 1; -+ unsigned int pitch = 1; -+ unsigned int line_no = 1; -+ unsigned int line_size = op->len >> -+ XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT; -+ u64 cmd = XDMA_CMD_AST2500_CMD_IRQ_EN | XDMA_CMD_AST2500_CMD_IRQ_BMC | -+ XDMA_CMD_AST2500_CMD_ID; -+ u64 cmd_pitch = (op->direction ? XDMA_CMD_AST2500_PITCH_UPSTREAM : 0) | -+ XDMA_CMD_AST2500_PITCH_ID; ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ dev_dbg(ctx->dev, "xdma %s ast2500: bmc[%08llx] len[%08x] host[%08x]\n", -+ op->direction ? "upstream" : "downstream", bmc_addr, op->len, -+ (u32)op->host_addr); ++ spin_lock(&otp_state_lock); + -+ if (op->len > XDMA_CMD_AST2500_CMD_LINE_SIZE) { -+ unsigned int rem; -+ unsigned int total; ++ ctx->is_open = false; + -+ line_no = op->len / XDMA_CMD_AST2500_CMD_LINE_SIZE; -+ total = XDMA_CMD_AST2500_CMD_LINE_SIZE * line_no; -+ rem = (op->len - total) >> -+ XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT; -+ line_size = XDMA_CMD_AST2500_CMD_LINE_SIZE; -+ pitch = line_size >> XDMA_CMD_AST2500_PITCH_SHIFT; -+ line_size >>= XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT; ++ spin_unlock(&otp_state_lock); + -+ if (rem) { -+ u32 rbmc = bmc_addr + total; ++ return 0; ++} + -+ cmds[1].host_addr = op->host_addr + (u64)total; -+ cmds[1].pitch = cmd_pitch | -+ ((u64)rbmc & XDMA_CMD_AST2500_PITCH_ADDR) | -+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_HOST, 1) | -+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_BMC, 1); -+ cmds[1].cmd = cmd | -+ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_NO, 1) | -+ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_SIZE, -+ rem); -+ cmds[1].reserved = 0ULL; ++static const struct file_operations otp_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = otp_ioctl, ++ .open = otp_open, ++ .release = otp_release, ++}; + -+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, -+ 16, 1, &cmds[1], sizeof(*cmds), -+ true); ++static const struct of_device_id aspeed_otp_of_matches[] = { ++ { .compatible = "aspeed,ast2600-sbc" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); + -+ cmd &= ~(XDMA_CMD_AST2500_CMD_IRQ_EN | -+ XDMA_CMD_AST2500_CMD_IRQ_BMC); ++static int aspeed_otp_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct regmap *scu; ++ struct aspeed_otp *priv; ++ struct resource *res; ++ u32 revid0, revid1; ++ int rc; + -+ rc++; -+ } ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ glob_ctx = priv; ++ if (!priv) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; + } + -+ cmds[0].host_addr = op->host_addr; -+ cmds[0].pitch = cmd_pitch | -+ (bmc_addr & XDMA_CMD_AST2500_PITCH_ADDR) | -+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_HOST, pitch) | -+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_BMC, pitch); -+ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_NO, line_no) | -+ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_SIZE, line_size); -+ cmds[0].reserved = 0ULL; ++ priv->reg_base = devm_ioremap_resource(&pdev->dev, res); ++ if (!priv->reg_base) ++ return -EIO; + -+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, -+ sizeof(*cmds), true); ++ scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); ++ if (IS_ERR(scu)) { ++ dev_err(dev, "failed to find 2600 SCU regmap\n"); ++ return PTR_ERR(scu); ++ } ++ ++ regmap_read(scu, ASPEED_REVISION_ID0, &revid0); ++ regmap_read(scu, ASPEED_REVISION_ID1, &revid1); ++ ++ priv->otp_ver = chip_version(revid0, revid1); ++ ++ if (priv->otp_ver == -1) { ++ dev_err(dev, "invalid SCU\n"); ++ return -EINVAL; ++ } ++ ++ priv->data = kmalloc(8192, GFP_KERNEL); ++ if (!priv->data) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ ++ /* Set up the miscdevice */ ++ priv->miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->miscdev.name = "aspeed-otp"; ++ priv->miscdev.fops = &otp_fops; ++ ++ /* Register the device */ ++ rc = misc_register(&priv->miscdev); ++ if (rc) { ++ dev_err(dev, "Unable to register device\n"); ++ return rc; ++ } + -+ return rc; ++ return 0; +} + -+static unsigned int aspeed_xdma_ast2600_set_cmd(struct aspeed_xdma *ctx, -+ struct aspeed_xdma_cmd cmds[2], -+ struct aspeed_xdma_op *op, -+ u64 bmc_addr) ++static void aspeed_otp_remove(struct platform_device *pdev) +{ -+ unsigned int rc = 1; -+ unsigned int pitch = 1; -+ unsigned int line_no = 1; -+ unsigned int line_size = op->len; -+ u64 cmd = XDMA_CMD_AST2600_CMD_IRQ_BMC | -+ (op->direction ? XDMA_CMD_AST2600_CMD_UPSTREAM : 0); -+ -+ if (op->host_addr & 0xffffffff00000000ULL || -+ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) -+ cmd |= XDMA_CMD_AST2600_CMD_64_EN; -+ -+ dev_dbg(ctx->dev, "xdma %s ast2600: bmc[%08llx] len[%08x] host[%016llx]\n", -+ op->direction ? "upstream" : "downstream", -+ bmc_addr, op->len, op->host_addr); ++ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); + -+ if ((op->host_addr & 0xff) + op->len > XDMA_CMD_AST2600_CMD_LINE_SIZE) { -+ unsigned int rem; -+ unsigned int total; ++ kfree(ctx->data); ++ misc_deregister(&ctx->miscdev); ++} + -+ line_no = op->len / XDMA_CMD_AST2600_CMD_MULTILINE_SIZE; -+ total = XDMA_CMD_AST2600_CMD_MULTILINE_SIZE * line_no; -+ rem = op->len - total; -+ line_size = XDMA_CMD_AST2600_CMD_MULTILINE_SIZE; -+ pitch = line_size; ++static struct platform_driver aspeed_otp_driver = { ++ .probe = aspeed_otp_probe, ++ .remove = aspeed_otp_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_otp_of_matches, ++ }, ++}; + -+ if (rem) { -+ u32 rbmc = bmc_addr + total; ++module_platform_driver(aspeed_otp_driver); + -+ cmds[1].host_addr = op->host_addr + (u64)total; -+ cmds[1].pitch = -+ ((u64)rbmc & XDMA_CMD_AST2600_PITCH_ADDR) | -+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_HOST, 1) | -+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_BMC, 1); -+ cmds[1].cmd = cmd | -+ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_NO, 1) | -+ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_SIZE, -+ rem); -+ cmds[1].reserved = 0ULL; ++MODULE_AUTHOR("Neal Liu "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ASPEED OTP Driver"); +diff --git a/drivers/soc/aspeed/ast2700-otp.c b/drivers/soc/aspeed/ast2700-otp.c +--- a/drivers/soc/aspeed/ast2700-otp.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/ast2700-otp.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,565 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2024 Aspeed Technology Inc. ++ */ + -+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, -+ 16, 1, &cmds[1], sizeof(*cmds), -+ true); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ cmd &= ~XDMA_CMD_AST2600_CMD_IRQ_BMC; ++static DEFINE_SPINLOCK(otp_state_lock); + -+ rc++; -+ } -+ } ++/*********************** ++ * * ++ * OTP regs definition * ++ * * ++ ***********************/ ++#define OTP_REG_SIZE 0x200 + -+ cmds[0].host_addr = op->host_addr; -+ cmds[0].pitch = (bmc_addr & XDMA_CMD_AST2600_PITCH_ADDR) | -+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_HOST, pitch) | -+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_BMC, pitch); -+ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_NO, line_no) | -+ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_SIZE, line_size); -+ cmds[0].reserved = 0ULL; ++#define OTP_PASSWD 0x349fe38a ++#define OTP_CMD_READ 0x23b1e361 ++#define OTP_CMD_PROG 0x23b1e364 ++#define OTP_CMD_PROG_MULTI 0x23b1e365 ++#define OTP_CMD_CMP 0x23b1e363 ++#define OTP_CMD_BIST 0x23b1e368 + -+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, -+ sizeof(*cmds), true); ++#define OTP_CMD_OFFSET 0x20 ++#define OTP_MASTER OTP_M0 + -+ return rc; -+} ++#define OTP_KEY 0x0 ++#define OTP_CMD (OTP_MASTER * OTP_CMD_OFFSET + 0x4) ++#define OTP_WDATA_0 (OTP_MASTER * OTP_CMD_OFFSET + 0x8) ++#define OTP_WDATA_1 (OTP_MASTER * OTP_CMD_OFFSET + 0xc) ++#define OTP_WDATA_2 (OTP_MASTER * OTP_CMD_OFFSET + 0x10) ++#define OTP_WDATA_3 (OTP_MASTER * OTP_CMD_OFFSET + 0x14) ++#define OTP_STATUS (OTP_MASTER * OTP_CMD_OFFSET + 0x18) ++#define OTP_ADDR (OTP_MASTER * OTP_CMD_OFFSET + 0x1c) ++#define OTP_RDATA (OTP_MASTER * OTP_CMD_OFFSET + 0x20) + -+static unsigned int aspeed_xdma_ast2700_set_cmd(struct aspeed_xdma *ctx, -+ struct aspeed_xdma_cmd cmds[2], -+ struct aspeed_xdma_op *op, -+ u64 bmc_addr) -+{ -+ unsigned int rc = 1; -+ unsigned int pitch = 1; -+ unsigned int line_no = 1; -+ unsigned int line_size = op->len; -+ u64 cmd = XDMA_CMD_AST2700_CMD_IRQ_BMC | -+ (op->direction ? XDMA_CMD_AST2700_CMD_UPSTREAM : 0); ++#define OTP_DBG00 0x0C4 ++#define OTP_DBG01 0x0C8 ++#define OTP_MASTER_PID 0x0D0 ++#define OTP_ECC_EN 0x0D4 ++#define OTP_CMD_LOCK 0x0D8 ++#define OTP_SW_RST 0x0DC ++#define OTP_SLV_ID 0x0E0 ++#define OTP_PMC_CQ 0x0E4 ++#define OTP_FPGA 0x0EC ++#define OTP_CLR_FPGA 0x0F0 ++#define OTP_REGION_ROM_PATCH 0x100 ++#define OTP_REGION_OTPCFG 0x104 ++#define OTP_REGION_OTPSTRAP 0x108 ++#define OTP_REGION_OTPSTRAP_EXT 0x10C ++#define OTP_REGION_SECURE0 0x120 ++#define OTP_REGION_SECURE0_RANGE 0x124 ++#define OTP_REGION_SECURE1 0x128 ++#define OTP_REGION_SECURE1_RANGE 0x12C ++#define OTP_REGION_SECURE2 0x130 ++#define OTP_REGION_SECURE2_RANGE 0x134 ++#define OTP_REGION_SECURE3 0x138 ++#define OTP_REGION_SECURE3_RANGE 0x13C ++#define OTP_REGION_USR0 0x140 ++#define OTP_REGION_USR0_RANGE 0x144 ++#define OTP_REGION_USR1 0x148 ++#define OTP_REGION_USR1_RANGE 0x14C ++#define OTP_REGION_USR2 0x150 ++#define OTP_REGION_USR2_RANGE 0x154 ++#define OTP_REGION_USR3 0x158 ++#define OTP_REGION_USR3_RANGE 0x15C ++#define OTP_REGION_CALIPTRA_0 0x160 ++#define OTP_REGION_CALIPTRA_0_RANGE 0x164 ++#define OTP_REGION_CALIPTRA_1 0x168 ++#define OTP_REGION_CALIPTRA_1_RANGE 0x16C ++#define OTP_REGION_CALIPTRA_2 0x170 ++#define OTP_REGION_CALIPTRA_2_RANGE 0x174 ++#define OTP_REGION_CALIPTRA_3 0x178 ++#define OTP_REGION_CALIPTRA_3_RANGE 0x17C ++#define OTP_RBP_SOC_SVN 0x180 ++#define OTP_RBP_SOC_KEYRETIRE 0x184 ++#define OTP_RBP_CALIP_SVN 0x188 ++#define OTP_RBP_CALIP_KEYRETIRE 0x18C ++#define OTP_PUF 0x1A0 ++#define OTP_MASTER_ID 0x1B0 ++#define OTP_MASTER_ID_EXT 0x1B4 ++#define OTP_R_MASTER_ID 0x1B8 ++#define OTP_R_MASTER_ID_EXT 0x1BC ++#define OTP_SOC_ECCKEY 0x1C0 ++#define OTP_SEC_BOOT_EN 0x1C4 ++#define OTP_SOC_KEY 0x1C8 ++#define OTP_CALPITRA_MANU_KEY 0x1CC ++#define OTP_CALPITRA_OWNER_KEY 0x1D0 ++#define OTP_FW_ID_LSB 0x1D4 ++#define OTP_FW_ID_MSB 0x1D8 ++#define OTP_CALIP_FMC_SVN 0x1DC ++#define OTP_CALIP_RUNTIME_SVN0 0x1E0 ++#define OTP_CALIP_RUNTIME_SVN1 0x1E4 ++#define OTP_CALIP_RUNTIME_SVN2 0x1E8 ++#define OTP_CALIP_RUNTIME_SVN3 0x1EC ++#define OTP_SVN_WLOCK 0x1F0 ++#define OTP_INTR_EN 0x200 ++#define OTP_INTR_STS 0x204 ++#define OTP_INTR_MID 0x208 ++#define OTP_INTR_FUNC_INFO 0x20C ++#define OTP_INTR_M_INFO 0x210 ++#define OTP_INTR_R_INFO 0x214 + -+ if (op->host_addr & 0xffffffff00000000ULL || -+ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) -+ cmd |= XDMA_CMD_AST2700_CMD_64_EN; ++#define OTP_PMC 0x400 ++#define OTP_DAP 0x500 + -+ dev_dbg(ctx->dev, "xdma %s ast2700: bmc[%016llx] len[%08x] host[%016llx]\n", -+ op->direction ? "upstream" : "downstream", -+ bmc_addr, op->len, op->host_addr); ++/* OTP status: [0] */ ++#define OTP_STS_IDLE 0x0 ++#define OTP_STS_BUSY 0x1 + -+ if (op->len > XDMA_CMD_AST2700_CMD_LINE_SIZE) { -+ unsigned int rem; -+ unsigned int total; ++/* OTP cmd status: [7:4] */ ++#define OTP_GET_CMD_STS(x) (((x) & 0xF0) >> 4) ++#define OTP_STS_PASS 0x0 ++#define OTP_STS_FAIL 0x1 ++#define OTP_STS_CMP_FAIL 0x2 ++#define OTP_STS_REGION_FAIL 0x3 ++#define OTP_STS_MASTER_FAIL 0x4 + -+ line_no = op->len / XDMA_CMD_AST2700_CMD_MULTILINE_SIZE; -+ total = XDMA_CMD_AST2700_CMD_MULTILINE_SIZE * line_no; -+ rem = op->len - total; -+ line_size = XDMA_CMD_AST2700_CMD_MULTILINE_SIZE; -+ pitch = line_size; ++/* OTP ECC EN */ ++#define ECC_ENABLE 0x1 ++#define ECC_DISABLE 0x0 ++#define ECCBRP_EN BIT(0) + -+ if (rem) { -+ u64 rbmc = bmc_addr + total; ++#define ROM_REGION_START_ADDR 0x0 ++#define ROM_REGION_END_ADDR 0x3e0 ++#define RBP_REGION_START_ADDR ROM_REGION_END_ADDR ++#define RBP_REGION_END_ADDR 0x400 ++#define CONF_REGION_START_ADDR RBP_REGION_END_ADDR ++#define CONF_REGION_END_ADDR 0x420 ++#define STRAP_REGION_START_ADDR CONF_REGION_END_ADDR ++#define STRAP_REGION_END_ADDR 0x430 ++#define STRAPEXT_REGION_START_ADDR STRAP_REGION_END_ADDR ++#define STRAPEXT_REGION_END_ADDR 0x440 ++#define USER_REGION_START_ADDR STRAPEXT_REGION_END_ADDR ++#define USER_REGION_END_ADDR 0x1000 ++#define SEC_REGION_START_ADDR USER_REGION_END_ADDR ++#define SEC_REGION_END_ADDR 0x1c00 ++#define CAL_REGION_START_ADDR SEC_REGION_END_ADDR ++#define CAL_REGION_END_ADDR 0x1f80 ++#define SW_PUF_REGION_START_ADDR CAL_REGION_END_ADDR ++#define SW_PUF_REGION_END_ADDR 0x1fc0 ++#define HW_PUF_REGION_START_ADDR SW_PUF_REGION_END_ADDR ++#define HW_PUF_REGION_END_ADDR 0x2000 + -+ cmds[1].host_addr = op->host_addr + (u64)total; -+ cmds[1].pitch = -+ FIELD_PREP(XDMA_CMD_AST2700_PITCH_HOST, 1) | -+ FIELD_PREP(XDMA_CMD_AST2700_PITCH_BMC, 1); -+ cmds[1].cmd = cmd | -+ FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_NO, 1) | -+ FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_SIZE, -+ rem); -+ cmds[1].reserved = rbmc & XDMA_CMD_AST2700_BMC_ADDR; ++#define OTP_MEMORY_SIZE (HW_PUF_REGION_END_ADDR * 2) + -+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, -+ 16, 1, &cmds[1], sizeof(*cmds), -+ true); ++#define OTP_TIMEOUT_US 10000 + -+ cmd &= ~XDMA_CMD_AST2700_CMD_IRQ_BMC; ++/* OTPSTRAP */ ++#define OTPSTRAP0_ADDR STRAP_REGION_START_ADDR ++#define OTPSTRAP14_ADDR (OTPSTRAP0_ADDR + 0xe) + -+ rc++; -+ } -+ } -+ cmds[0].host_addr = op->host_addr; -+ cmds[0].pitch = -+ FIELD_PREP(XDMA_CMD_AST2700_PITCH_HOST, pitch) | -+ FIELD_PREP(XDMA_CMD_AST2700_PITCH_BMC, pitch); -+ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_NO, line_no) | -+ FIELD_PREP(XDMA_CMD_AST2700_CMD_LINE_SIZE, line_size); -+ cmds[0].reserved = bmc_addr & XDMA_CMD_AST2700_BMC_ADDR; ++#define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) ++#define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff) ++#define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff) ++#define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff) ++#define OTPTOOL_COMPT_VERSION 2 + -+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, -+ sizeof(*cmds), true); ++enum otp_error_code { ++ OTP_SUCCESS, ++ OTP_READ_FAIL, ++ OTP_PROG_FAIL, ++ OTP_CMP_FAIL, ++}; + -+ return rc; -+} ++enum aspeed_otp_master_id { ++ OTP_M0 = 0, ++ OTP_M1, ++ OTP_M2, ++ OTP_M3, ++ OTP_M4, ++ OTP_M5, ++ OTP_MID_MAX, ++}; + -+static int aspeed_xdma_start(struct aspeed_xdma *ctx, unsigned int num_cmds, -+ struct aspeed_xdma_cmd cmds[2], bool upstream, -+ struct aspeed_xdma_client *client) -+{ -+ unsigned int i; -+ int rc = -EBUSY; -+ unsigned long flags; ++struct aspeed_otp { ++ struct miscdevice miscdev; ++ struct device *dev; ++ void __iomem *base; ++ u32 chip_revid0; ++ u32 chip_revid1; ++ bool is_open; ++ int gbl_ecc_en; ++ u8 *data; ++}; + -+ spin_lock_irqsave(&ctx->engine_lock, flags); -+ if (ctx->in_reset) -+ goto unlock; ++enum otp_ioctl_cmds { ++ GET_ECC_STATUS = 1, ++ SET_ECC_ENABLE, ++}; + -+ spin_lock(&ctx->client_lock); -+ if (ctx->current_client) { -+ spin_unlock(&ctx->client_lock); -+ goto unlock; -+ } ++enum otp_ecc_codes { ++ OTP_ECC_MISMATCH = -1, ++ OTP_ECC_DISABLE = 0, ++ OTP_ECC_ENABLE = 1, ++}; + -+ client->error = false; -+ client->in_progress = true; -+ ctx->current_client = client; -+ spin_unlock(&ctx->client_lock); ++static void otp_unlock(struct device *dev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); + -+ ctx->upstream = upstream; -+ for (i = 0; i < num_cmds; ++i) { -+ trace_xdma_start(ctx, &cmds[i]); -+ /* -+ * Use memcpy_toio here to get some barriers before starting -+ * the operation. The command(s) need to be in physical memory -+ * before the XDMA engine starts. -+ */ -+ memcpy_toio(&ctx->cmdq[ctx->cmd_idx], &cmds[i], -+ sizeof(struct aspeed_xdma_cmd)); -+ ctx->cmd_idx = (ctx->cmd_idx + 1) % XDMA_NUM_CMDS; -+ } ++ writel(OTP_PASSWD, ctx->base + OTP_KEY); ++} + -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, -+ ctx->cmd_idx * ctx->chip->queue_entry_size); -+ rc = 0; ++static void otp_lock(struct device *dev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); + -+unlock: -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); -+ return rc; ++ writel(0x1, ctx->base + OTP_KEY); +} + -+static void aspeed_xdma_done(struct aspeed_xdma *ctx, bool error) ++static int wait_complete(struct device *dev) +{ -+ unsigned long flags; ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ int ret; ++ u32 val; + -+ spin_lock_irqsave(&ctx->client_lock, flags); -+ if (ctx->current_client) { -+ ctx->current_client->error = error; -+ ctx->current_client->in_progress = false; -+ ctx->current_client = NULL; -+ } -+ spin_unlock_irqrestore(&ctx->client_lock, flags); ++ ret = readl_poll_timeout(ctx->base + OTP_STATUS, val, (val == 0x0), ++ 1, OTP_TIMEOUT_US); ++ if (ret) ++ dev_warn(dev, "timeout. sts:0x%x\n", val); + -+ wake_up_interruptible_all(&ctx->wait); ++ return ret; +} + -+static irqreturn_t aspeed_xdma_irq(int irq, void *arg) ++static int otp_read_data(struct aspeed_otp *ctx, u32 offset, u16 *data) +{ -+ struct aspeed_xdma *ctx = arg; -+ u32 status; ++ struct device *dev = ctx->dev; ++ int ret; + -+ spin_lock(&ctx->engine_lock); -+ status = aspeed_xdma_readl(ctx, ctx->chip->regs.status); ++ writel(ctx->gbl_ecc_en, ctx->base + OTP_ECC_EN); ++ writel(offset, ctx->base + OTP_ADDR); ++ writel(OTP_CMD_READ, ctx->base + OTP_CMD); ++ ret = wait_complete(dev); ++ if (ret) ++ return OTP_READ_FAIL; + -+ trace_xdma_irq(status); ++ data[0] = readl(ctx->base + OTP_RDATA); + -+ if (status & ctx->chip->status_bits.ds_dirty) { -+ aspeed_xdma_done(ctx, true); -+ } else { -+ if (status & ctx->chip->status_bits.us_comp) { -+ if (ctx->upstream) -+ aspeed_xdma_done(ctx, false); -+ } ++ return 0; ++} + -+ if (status & ctx->chip->status_bits.ds_comp) { -+ if (!ctx->upstream) -+ aspeed_xdma_done(ctx, false); -+ } -+ } ++static int otp_prog_data(struct aspeed_otp *ctx, u32 offset, u16 data) ++{ ++ struct device *dev = ctx->dev; ++ int ret; + -+ aspeed_xdma_writel(ctx, ctx->chip->regs.status, status); -+ spin_unlock(&ctx->engine_lock); ++ writel(ctx->gbl_ecc_en, ctx->base + OTP_ECC_EN); ++ writel(offset, ctx->base + OTP_ADDR); ++ writel(data, ctx->base + OTP_WDATA_0); ++ writel(OTP_CMD_PROG, ctx->base + OTP_CMD); ++ ret = wait_complete(dev); ++ if (ret) ++ return OTP_PROG_FAIL; + -+ return IRQ_HANDLED; ++ return 0; +} + -+static void aspeed_xdma_reset(struct aspeed_xdma *ctx) ++static int otp_prog_multi_data(struct aspeed_otp *ctx, u32 offset, u32 *data, int count) +{ -+ unsigned long flags; ++ struct device *dev = ctx->dev; ++ int ret; + -+ trace_xdma_reset(ctx); ++ writel(ctx->gbl_ecc_en, ctx->base + OTP_ECC_EN); ++ writel(offset, ctx->base + OTP_ADDR); ++ for (int i = 0; i < count; i++) ++ writel(data[i], ctx->base + OTP_WDATA_0 + 4 * i); + -+ reset_control_assert(ctx->reset); -+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, -+ XDMA_ENGINE_SETUP_TIME_MAX_US); -+ reset_control_deassert(ctx->reset); -+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, -+ XDMA_ENGINE_SETUP_TIME_MAX_US); ++ writel(OTP_CMD_PROG_MULTI, ctx->base + OTP_CMD); ++ ret = wait_complete(dev); ++ if (ret) ++ return OTP_PROG_FAIL; + -+ aspeed_xdma_init_eng(ctx); ++ return 0; ++} + -+ aspeed_xdma_done(ctx, true); ++static int aspeed_otp_read(struct aspeed_otp *ctx, int offset, ++ void *buf, int size) ++{ ++ struct device *dev = ctx->dev; ++ u16 *data = buf; ++ int ret; + -+ spin_lock_irqsave(&ctx->engine_lock, flags); -+ ctx->in_reset = false; -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ otp_unlock(dev); ++ for (int i = 0; i < size; i++) { ++ ret = otp_read_data(ctx, offset + i, data + i); ++ if (ret) { ++ dev_warn(ctx->dev, "read failed\n"); ++ break; ++ } ++ } + -+ wake_up_interruptible(&ctx->wait); ++ otp_lock(dev); ++ return ret; +} + -+static void aspeed_xdma_reset_work(struct work_struct *work) ++static int aspeed_otp_write(struct aspeed_otp *ctx, int offset, ++ const void *buf, int size) +{ -+ struct aspeed_xdma *ctx = container_of(work, struct aspeed_xdma, -+ reset_work); ++ struct device *dev = ctx->dev; ++ u32 *data32 = (u32 *)buf; ++ u16 *data = (u16 *)buf; ++ int ret; + -+ aspeed_xdma_reset(ctx); ++ otp_unlock(dev); ++ ++ if (size == 1) ++ ret = otp_prog_data(ctx, offset, data[0]); ++ else ++ ret = otp_prog_multi_data(ctx, offset, data32, size / 2); ++ ++ if (ret) ++ dev_warn(ctx->dev, "prog failed\n"); ++ ++ otp_lock(dev); ++ return ret; +} + -+static irqreturn_t aspeed_xdma_pcie_irq(int irq, void *arg) ++static int aspeed_otp_ecc_en(struct aspeed_otp *ctx) +{ -+ struct aspeed_xdma *ctx = arg; ++ struct device *dev = ctx->dev; ++ int ret = 0; + -+ trace_xdma_perst(ctx); ++ /* Check ecc is already enabled */ ++ if (ctx->gbl_ecc_en == 1) ++ return 0; + -+ spin_lock(&ctx->engine_lock); -+ if (ctx->in_reset) { -+ spin_unlock(&ctx->engine_lock); -+ return IRQ_HANDLED; ++ otp_unlock(dev); ++ ++ /* enable cfg ecc */ ++ ret = otp_prog_data(ctx, OTPSTRAP14_ADDR, 0x1); ++ if (ret) { ++ dev_warn(dev, "%s: prog failed\n", __func__); ++ goto end; + } + -+ ctx->in_reset = true; -+ spin_unlock(&ctx->engine_lock); ++ ctx->gbl_ecc_en = 1; ++end: ++ otp_lock(dev); + -+ schedule_work(&ctx->reset_work); -+ return IRQ_HANDLED; ++ return ret; +} + -+static ssize_t aspeed_xdma_write(struct file *file, const char __user *buf, -+ size_t len, loff_t *offset) ++static long aspeed_otp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ -+ int rc; -+ unsigned int num_cmds; -+ struct aspeed_xdma_op op; -+ struct aspeed_xdma_cmd cmds[2]; -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; -+ -+ if (len != sizeof(op)) -+ return -EINVAL; ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++ void __user *argp = (void __user *)arg; ++ struct otp_revid revid; ++ struct otp_read rdata; ++ struct otp_prog pdata; ++ int ret = 0; + -+ if (READ_ONCE(client->in_progress)) -+ return -EBUSY; ++ switch (cmd) { ++ case ASPEED_OTP_READ_DATA: ++ if (copy_from_user(&rdata, argp, sizeof(struct otp_read))) ++ return -EFAULT; + -+ if (copy_from_user(&op, buf, len)) -+ return -EFAULT; ++ ret = aspeed_otp_read(ctx, rdata.offset, ctx->data, rdata.len); ++ if (ret) ++ return -EFAULT; + -+ if (!op.len || op.len > client->size || -+ op.direction > ASPEED_XDMA_DIRECTION_UPSTREAM) -+ return -EINVAL; ++ if (copy_to_user(rdata.data, ctx->data, rdata.len * 2)) ++ return -EFAULT; + -+ num_cmds = ctx->chip->set_cmd(ctx, cmds, &op, client->phys); -+ do { -+ rc = aspeed_xdma_start(ctx, num_cmds, cmds, !!op.direction, -+ client); -+ if (!rc) -+ break; ++ break; + -+ if ((file->f_flags & O_NONBLOCK) || rc != -EBUSY) -+ return rc; ++ case ASPEED_OTP_PROG_DATA: ++ if (copy_from_user(&pdata, argp, sizeof(struct otp_prog))) ++ return -EFAULT; + -+ rc = wait_event_interruptible(ctx->wait, -+ !(ctx->current_client || -+ ctx->in_reset)); -+ } while (!rc); ++ ret = aspeed_otp_write(ctx, pdata.w_offset, pdata.data, pdata.len); ++ break; + -+ if (rc) -+ return -EINTR; ++ case ASPEED_OTP_GET_ECC: ++ if (copy_to_user(argp, &ctx->gbl_ecc_en, sizeof(ctx->gbl_ecc_en))) ++ return -EFAULT; ++ break; + -+ if (!(file->f_flags & O_NONBLOCK)) { -+ rc = wait_event_interruptible(ctx->wait, !client->in_progress); -+ if (rc) -+ return -EINTR; ++ case ASPEED_OTP_SET_ECC: ++ ret = aspeed_otp_ecc_en(ctx); ++ break; + -+ if (client->error) -+ return -EIO; ++ case ASPEED_OTP_GET_REVID: ++ revid.revid0 = ctx->chip_revid0; ++ revid.revid1 = ctx->chip_revid1; ++ if (copy_to_user(argp, &revid, sizeof(struct otp_revid))) ++ return -EFAULT; ++ break; ++ default: ++ dev_warn(ctx->dev, "cmd 0x%x is not supported\n", cmd); ++ break; + } + -+ return len; ++ return ret; +} + -+static __poll_t aspeed_xdma_poll(struct file *file, -+ struct poll_table_struct *wait) ++static int aspeed_otp_ecc_init(struct device *dev) +{ -+ __poll_t mask = 0; -+ __poll_t req = poll_requested_events(wait); -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; -+ -+ if (req & (EPOLLIN | EPOLLRDNORM)) { -+ if (READ_ONCE(client->in_progress)) -+ poll_wait(file, &ctx->wait, wait); ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ int ret; ++ u32 val; + -+ if (!READ_ONCE(client->in_progress)) { -+ if (READ_ONCE(client->error)) -+ mask |= EPOLLERR; -+ else -+ mask |= EPOLLIN | EPOLLRDNORM; -+ } -+ } ++ otp_unlock(dev); + -+ if (req & (EPOLLOUT | EPOLLWRNORM)) { -+ if (READ_ONCE(ctx->current_client)) -+ poll_wait(file, &ctx->wait, wait); ++ /* Check cfg_ecc_en */ ++ writel(0, ctx->base + OTP_ECC_EN); ++ writel(OTPSTRAP14_ADDR, ctx->base + OTP_ADDR); ++ writel(OTP_CMD_READ, ctx->base + OTP_CMD); ++ ret = wait_complete(dev); ++ if (ret) ++ return OTP_READ_FAIL; + -+ if (!READ_ONCE(ctx->current_client)) -+ mask |= EPOLLOUT | EPOLLWRNORM; -+ } ++ val = readl(ctx->base + OTP_RDATA); ++ if (val & 0x1) ++ ctx->gbl_ecc_en = 0x1; ++ else ++ ctx->gbl_ecc_en = 0x0; + -+ if (mask) -+ aspeed_xdma_reset(ctx); ++ otp_lock(dev); + -+ return mask; ++ return 0; +} + -+static long aspeed_xdma_ioctl(struct file *file, unsigned int cmd, -+ unsigned long param) ++static int aspeed_otp_open(struct inode *inode, struct file *file) +{ -+ unsigned long flags; -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ switch (cmd) { -+ case ASPEED_XDMA_IOCTL_RESET: -+ spin_lock_irqsave(&ctx->engine_lock, flags); -+ if (ctx->in_reset) { -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); -+ return 0; -+ } ++ spin_lock(&otp_state_lock); + -+ ctx->in_reset = true; -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ if (ctx->is_open) { ++ spin_unlock(&otp_state_lock); ++ return -EBUSY; ++ } + -+ if (READ_ONCE(ctx->current_client)) -+ dev_warn(ctx->dev, -+ "User reset with transfer in progress.\n"); ++ ctx->is_open = true; + -+ aspeed_xdma_reset(ctx); -+ break; -+ default: -+ return -EINVAL; -+ } ++ spin_unlock(&otp_state_lock); + + return 0; +} + -+static void aspeed_xdma_vma_close(struct vm_area_struct *vma) ++static int aspeed_otp_release(struct inode *inode, struct file *file) +{ -+ int rc; -+ struct aspeed_xdma_client *client = vma->vm_private_data; ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ rc = wait_event_interruptible(client->ctx->wait, !client->in_progress); -+ if (rc) -+ return; ++ spin_lock(&otp_state_lock); + -+ gen_pool_free(client->ctx->pool, (unsigned long)client->virt, -+ client->size); -+ trace_xdma_unmap(client); ++ ctx->is_open = false; + -+ client->virt = NULL; -+ client->phys = 0; -+ client->size = 0; ++ spin_unlock(&otp_state_lock); ++ ++ return 0; +} + -+static const struct vm_operations_struct aspeed_xdma_vm_ops = { -+ .close = aspeed_xdma_vma_close, ++static const struct file_operations otp_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = aspeed_otp_ioctl, ++ .open = aspeed_otp_open, ++ .release = aspeed_otp_release, +}; + -+static int aspeed_xdma_mmap(struct file *file, struct vm_area_struct *vma) ++static const struct of_device_id aspeed_otp_of_matches[] = { ++ { .compatible = "aspeed,ast2700-otp" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); ++ ++static int aspeed_otp_probe(struct platform_device *pdev) +{ ++ struct device *dev = &pdev->dev; ++ struct regmap *scu0, *scu1; ++ struct aspeed_otp *priv; ++ struct resource *res; + int rc; -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; -+ -+ /* restrict file to one mapping */ -+ if (client->size) -+ return -EBUSY; + -+ client->size = vma->vm_end - vma->vm_start; -+ client->virt = gen_pool_dma_alloc(ctx->pool, client->size, -+ &client->phys); -+ if (!client->virt) { -+ trace_xdma_mmap_error(client, 0UL); -+ client->phys = 0; -+ client->size = 0; ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) + return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; + } + -+ vma->vm_pgoff = (client->phys - ctx->mem_phys) >> PAGE_SHIFT; -+ vma->vm_ops = &aspeed_xdma_vm_ops; -+ vma->vm_private_data = client; -+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ priv->base = devm_ioremap_resource(&pdev->dev, res); ++ if (!priv->base) ++ return -EIO; + -+ rc = io_remap_pfn_range(vma, vma->vm_start, client->phys >> PAGE_SHIFT, -+ client->size, vma->vm_page_prot); -+ if (rc) { -+ dev_warn(ctx->dev, "mmap err: v[%08lx] to p[%pa], s[%08x]\n", -+ vma->vm_start, &client->phys, client->size); ++ scu0 = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu0"); ++ scu1 = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu1"); ++ if (IS_ERR(scu0) || IS_ERR(scu1)) { ++ dev_err(dev, "failed to find SCU regmap\n"); ++ return PTR_ERR(scu0) || PTR_ERR(scu1); ++ } + -+ gen_pool_free(ctx->pool, (unsigned long)client->virt, -+ client->size); ++ regmap_read(scu0, 0x0, &priv->chip_revid0); ++ regmap_read(scu1, 0x0, &priv->chip_revid1); + -+ trace_xdma_mmap_error(client, vma->vm_start); -+ client->virt = NULL; -+ client->phys = 0; -+ client->size = 0; ++ priv->dev = dev; ++ dev_set_drvdata(dev, priv); ++ ++ /* OTP ECC init */ ++ rc = aspeed_otp_ecc_init(dev); ++ if (rc) ++ return -EIO; ++ ++ priv->data = kmalloc(OTP_MEMORY_SIZE, GFP_KERNEL); ++ if (!priv->data) ++ return -ENOMEM; ++ ++ /* Set up the miscdevice */ ++ priv->miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->miscdev.name = "aspeed-otp"; ++ priv->miscdev.fops = &otp_fops; ++ ++ /* Register the device */ ++ rc = misc_register(&priv->miscdev); ++ if (rc) { ++ dev_err(dev, "Unable to register device\n"); + return rc; + } + -+ trace_xdma_mmap(client); -+ dev_dbg(ctx->dev, "mmap: v[%08lx] to p[%pa], s[%08x]\n", -+ vma->vm_start, &client->phys, client->size); ++ dev_info(dev, "Aspeed OTP driver successfully registered\n"); + + return 0; +} + -+static int aspeed_xdma_open(struct inode *inode, struct file *file) ++static void aspeed_otp_remove(struct platform_device *pdev) +{ -+ struct miscdevice *misc = file->private_data; -+ struct aspeed_xdma *ctx = container_of(misc, struct aspeed_xdma, misc); -+ struct aspeed_xdma_client *client = kzalloc(sizeof(*client), -+ GFP_KERNEL); -+ -+ if (!client) -+ return -ENOMEM; ++ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); + -+ kobject_get(&ctx->kobj); -+ client->ctx = ctx; -+ file->private_data = client; -+ return 0; ++ kfree(ctx->data); ++ misc_deregister(&ctx->miscdev); +} + -+static int aspeed_xdma_release(struct inode *inode, struct file *file) -+{ -+ bool reset = false; -+ unsigned long flags; -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; ++static struct platform_driver aspeed_otp_driver = { ++ .probe = aspeed_otp_probe, ++ .remove = aspeed_otp_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_otp_of_matches, ++ }, ++}; + -+ spin_lock_irqsave(&ctx->client_lock, flags); -+ if (client == ctx->current_client) { -+ spin_lock(&ctx->engine_lock); -+ if (ctx->in_reset) { -+ ctx->current_client = NULL; -+ } else { -+ ctx->in_reset = true; -+ reset = true; -+ } -+ spin_unlock(&ctx->engine_lock); -+ } -+ spin_unlock_irqrestore(&ctx->client_lock, flags); ++module_platform_driver(aspeed_otp_driver); + -+ if (reset) -+ aspeed_xdma_reset(ctx); ++MODULE_AUTHOR("Neal Liu "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ASPEED OTP Driver"); +diff --git a/drivers/soc/aspeed/espi/Kconfig b/drivers/soc/aspeed/espi/Kconfig +--- a/drivers/soc/aspeed/espi/Kconfig 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/Kconfig 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,22 @@ ++menu "ASPEED eSPI drivers" + -+ if (client->virt) { -+ gen_pool_free(ctx->pool, (unsigned long)client->virt, -+ client->size); -+ trace_xdma_unmap(client); -+ } ++config ASPEED_ESPI ++ tristate "ASPEED eSPI slave driver" ++ help ++ Enable driver support for Aspeed AST2700 eSPI engine. The eSPI engine ++ plays as a slave device in BMC to communicate with the Host over ++ the eSPI interface. The four eSPI channels, namely peripheral, ++ virtual wire, out-of-band, and flash are supported. + -+ kfree(client); -+ kobject_put(&ctx->kobj); -+ return 0; -+} ++config AST2700_RTC_OVER_ESPI ++ tristate "ASPEED AST2700 RTC over eSPI drvier" ++ depends on HAS_IOMEM ++ help ++ Enable driver support for Aspeed AST2700 RTC over eSPI function. ++ Periodically copies RAM content from a RTC tm to a memory-mapped eSPI region. + -+static const struct file_operations aspeed_xdma_fops = { -+ .owner = THIS_MODULE, -+ .write = aspeed_xdma_write, -+ .poll = aspeed_xdma_poll, -+ .unlocked_ioctl = aspeed_xdma_ioctl, -+ .mmap = aspeed_xdma_mmap, -+ .open = aspeed_xdma_open, -+ .release = aspeed_xdma_release, -+}; ++config AST2700_INTEL_ESPI_MMBI ++ bool "Enable support for AST2700 ESPI MMBI controller with Intel PCH host" ++ depends on ASPEED_ESPI + -+static int aspeed_xdma_init_scu(struct aspeed_xdma *ctx, struct device *dev) -+{ -+ struct regmap *scu = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "aspeed,scu"); ++endmenu +diff --git a/drivers/soc/aspeed/espi/Makefile b/drivers/soc/aspeed/espi/Makefile +--- a/drivers/soc/aspeed/espi/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/Makefile 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,7 @@ ++obj-$(CONFIG_ASPEED_ESPI) += \ ++ ast2700-espi.o \ ++ ast2600-espi.o \ ++ ast2500-espi.o \ ++ aspeed-espi.o ++obj-$(CONFIG_AST2700_RTC_OVER_ESPI) += ast2700-rtc-over-espi.o ++obj-$(CONFIG_AST2700_INTEL_ESPI_MMBI) += ast2700-intel-espi-mmbi.o +\ No newline at end of file +diff --git a/drivers/soc/aspeed/espi/aspeed-espi-comm.h b/drivers/soc/aspeed/espi/aspeed-espi-comm.h +--- a/drivers/soc/aspeed/espi/aspeed-espi-comm.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/aspeed-espi-comm.h 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,215 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Aspeed eSPI protocol definitions and IOCTL methods ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#ifndef __ASPEED_ESPI_COMM_H__ ++#define __ASPEED_ESPI_COMM_H__ + -+ if (!IS_ERR(scu)) { -+ u32 selection; -+ bool pcie_device_bmc = true; -+ const u32 bmc = SCU_PCIE_CONF_BMC_EN | -+ SCU_PCIE_CONF_BMC_EN_MSI | SCU_PCIE_CONF_BMC_EN_IRQ | -+ SCU_PCIE_CONF_BMC_EN_DMA; -+ const u32 vga = SCU_PCIE_CONF_VGA_EN | -+ SCU_PCIE_CONF_VGA_EN_MSI | SCU_PCIE_CONF_VGA_EN_IRQ | -+ SCU_PCIE_CONF_VGA_EN_DMA; -+ const char *pcie = NULL; ++#include ++#include + -+ if (!of_property_read_string(dev->of_node, -+ "aspeed,pcie-device", &pcie)) { -+ if (!strcmp(pcie, "vga")) { -+ pcie_device_bmc = false; -+ } else if (strcmp(pcie, "bmc")) { -+ dev_err(dev, -+ "Invalid pcie-device property %s.\n", -+ pcie); -+ return -EINVAL; -+ } -+ } ++/* ++ * eSPI cycle type encoding ++ * ++ * Section 5.1 Cycle Types and Packet Format, ++ * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. ++ */ ++#define ESPI_PERIF_MEMRD32 0x00 ++#define ESPI_PERIF_MEMRD64 0x02 ++#define ESPI_PERIF_MEMWR32 0x01 ++#define ESPI_PERIF_MEMWR64 0x03 ++#define ESPI_PERIF_MSG 0x10 ++#define ESPI_PERIF_MSG_D 0x11 ++#define ESPI_PERIF_SUC_CMPLT 0x06 ++#define ESPI_PERIF_SUC_CMPLT_D_MIDDLE 0x09 ++#define ESPI_PERIF_SUC_CMPLT_D_FIRST 0x0b ++#define ESPI_PERIF_SUC_CMPLT_D_LAST 0x0d ++#define ESPI_PERIF_SUC_CMPLT_D_ONLY 0x0f ++#define ESPI_PERIF_UNSUC_CMPLT 0x0c ++#define ESPI_OOB_MSG 0x21 ++#define ESPI_FLASH_READ 0x00 ++#define ESPI_FLASH_WRITE 0x01 ++#define ESPI_FLASH_ERASE 0x02 ++#define ESPI_FLASH_SUC_CMPLT 0x06 ++#define ESPI_FLASH_SUC_CMPLT_D_MIDDLE 0x09 ++#define ESPI_FLASH_SUC_CMPLT_D_FIRST 0x0b ++#define ESPI_FLASH_SUC_CMPLT_D_LAST 0x0d ++#define ESPI_FLASH_SUC_CMPLT_D_ONLY 0x0f ++#define ESPI_FLASH_UNSUC_CMPLT 0x0c + -+ if (pcie_device_bmc) { -+ selection = bmc; -+ regmap_update_bits(scu, ctx->chip->scu_bmc_class, -+ SCU_BMC_CLASS_REV_MASK, -+ SCU_BMC_CLASS_REV_XDMA); -+ } else { -+ selection = vga; -+ } ++/* ++ * eSPI packet format structure ++ * ++ * Section 5.1 Cycle Types and Packet Format, ++ * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. ++ */ ++struct espi_comm_hdr { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++}; + -+ regmap_update_bits(scu, ctx->chip->scu_pcie_conf, bmc | vga, -+ selection); ++struct espi_perif_mem32 { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u32 addr_be; ++ u8 data[]; ++} __packed; + -+ if (ctx->chip->scu_misc_ctrl) { -+ regmap_update_bits(scu, ctx->chip->scu_misc_ctrl, -+ ctx->chip->scu_misc_mask, -+ ctx->chip->scu_misc_mask); ++struct espi_perif_mem64 { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u32 addr_be; ++ u8 data[]; ++} __packed; + -+ regmap_update_bits(scu, SCU_AST2600_DEBUG_CTRL, -+ ctx->chip->scu_disable_mask, 0); -+ } ++struct espi_perif_msg { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u8 msg_code; ++ u8 msg_byte[4]; ++ u8 data[]; ++} __packed; + -+ if (ctx->chip->scu_pcie_ctrl) { -+ regmap_update_bits(scu, ctx->chip->scu_pcie_ctrl, -+ SCU_AST2700_PCIE_CTRL_DMA_EN, -+ SCU_AST2700_PCIE_CTRL_DMA_EN); -+ } -+ } else { -+ dev_warn(dev, "Unable to configure PCIe: %ld; continuing.\n", -+ PTR_ERR(scu)); -+ } ++struct espi_perif_cmplt { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u8 data[]; ++} __packed; + -+ return 0; -+} ++struct espi_oob_msg { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u8 data[]; ++}; + -+static void aspeed_xdma_kobject_release(struct kobject *kobj) -+{ -+ struct aspeed_xdma *ctx = container_of(kobj, struct aspeed_xdma, kobj); ++struct espi_flash_rwe { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u32 addr_be; ++ u8 data[]; ++} __packed; + -+ if (ctx->pcie_irq >= 0) -+ free_irq(ctx->pcie_irq, ctx); ++struct espi_flash_cmplt { ++ u8 cyc; ++ u8 len_h : 4; ++ u8 tag : 4; ++ u8 len_l; ++ u8 data[]; ++} __packed; + -+ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE); ++#define ESPI_MAX_PLD_LEN BIT(12) + -+ gen_pool_destroy(ctx->pool); ++/* ++ * Aspeed IOCTL for eSPI raw packet send/receive ++ * ++ * This IOCTL interface works in the eSPI packet in/out paradigm. ++ * ++ * Only the virtual wire IOCTL is a special case which does not send ++ * or receive an eSPI packet. However, to keep a more consisten use from ++ * userspace, we make all of the four channel drivers serve through the ++ * IOCTL interface. ++ * ++ * For the eSPI packet format, refer to ++ * Section 5.1 Cycle Types and Packet Format, ++ * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. ++ * ++ * For the example user apps using these IOCTL, refer to ++ * https://github.com/AspeedTech-BMC/aspeed_app/tree/master/espi_test ++ */ ++#define __ASPEED_ESPI_IOCTL_MAGIC 0xb8 + -+ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt, -+ ctx->mem_coherent); ++/* ++ * we choose the longest header and the max payload size ++ * based on the Intel specification to define the maximum ++ * eSPI packet length ++ */ ++#define ESPI_MAX_PKT_LEN (sizeof(struct espi_perif_msg) + ESPI_MAX_PLD_LEN) + -+ if (ctx->reset_rc) -+ reset_control_put(ctx->reset_rc); -+ reset_control_put(ctx->reset); ++struct aspeed_espi_ioc { ++ u32 pkt_len; ++ u8 *pkt; ++}; + -+ clk_put(ctx->clock); ++/* ++ * Peripheral Channel (CH0) ++ * - ASPEED_ESPI_PERIF_PC_GET_RX ++ * Receive an eSPI Posted/Completion packet ++ * - ASPEED_ESPI_PERIF_PC_PUT_TX ++ * Transmit an eSPI Posted/Completion packet ++ * - ASPEED_ESPI_PERIF_NP_PUT_TX ++ * Transmit an eSPI Non-Posted packet ++ */ ++#define ASPEED_ESPI_PERIF_PC_GET_RX _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x00, struct aspeed_espi_ioc) ++#define ASPEED_ESPI_PERIF_PC_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x01, struct aspeed_espi_ioc) ++#define ASPEED_ESPI_PERIF_NP_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x02, struct aspeed_espi_ioc) ++/* ++ * Virtual Wire Channel (CH1) ++ * - ASPEED_ESPI_VW_GET_GPIO_VAL ++ * Read the input value of GPIO over the VW channel ++ * - ASPEED_ESPI_VW_PUT_GPIO_VAL ++ * Write the output value of GPIO over the VW channel ++ * - ASPEED_ESPI_VW_GET_GPIO_VAL1 (new feature in AST2700) ++ * Read the input value1 of GPIO over the VW channel ++ * - ASPEED_ESPI_VW_PUT_GPIO_VAL1 (new feature in AST2700) ++ * Write the output value1 of GPIO over the VW channel ++ * - ASPEED_ESPI_VW_GET_PCH_GENERIC ++ * Read the input value of PCH Generic Indexes over the VW channel ++ * - ASPEED_ESPI_VW_PUT_PCH_GENERIC ++ * Write the output value of PCH Generic Indexes over the VW channel ++ */ ++#define ASPEED_ESPI_VW_GET_GPIO_VAL _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x10, u32) ++#define ASPEED_ESPI_VW_PUT_GPIO_VAL _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x11, u32) ++#ifdef CONFIG_ARM64 ++#define ASPEED_ESPI_VW_GET_GPIO_VAL1 _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x12, u32) ++#define ASPEED_ESPI_VW_PUT_GPIO_VAL1 _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x13, u32) ++#endif ++#define ASPEED_ESPI_VW_GET_PCH_GENERIC _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x14, u32) ++#define ASPEED_ESPI_VW_PUT_PCH_GENERIC _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x15, u32) ++/* ++ * Out-of-band Channel (CH2) ++ * - ASPEED_ESPI_OOB_GET_RX ++ * Receive an eSPI OOB packet ++ * - ASPEED_ESPI_OOB_PUT_TX ++ * Transmit an eSPI OOB packet ++ */ ++#define ASPEED_ESPI_OOB_GET_RX _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x20, struct aspeed_espi_ioc) ++#define ASPEED_ESPI_OOB_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x21, struct aspeed_espi_ioc) ++/* ++ * Flash Channel (CH3) ++ * - ASPEED_ESPI_FLASH_GET_RX ++ * Receive an eSPI flash packet ++ * - ASPEED_ESPI_FLASH_PUT_TX ++ * Transmit an eSPI flash packet ++ */ ++#define ASPEED_ESPI_FLASH_GET_RX _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x30, struct aspeed_espi_ioc) ++#define ASPEED_ESPI_FLASH_PUT_TX _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ ++ 0x31, struct aspeed_espi_ioc) + -+ free_irq(ctx->irq, ctx); ++#endif +diff --git a/drivers/soc/aspeed/espi/aspeed-espi.c b/drivers/soc/aspeed/espi/aspeed-espi.c +--- a/drivers/soc/aspeed/espi/aspeed-espi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/aspeed-espi.c 2026-09-09 15:51:44.719238056 +0000 +@@ -0,0 +1,256 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Unified Aspeed eSPI driver (AST2500/AST2600/AST2700) ++ * ++ * This wraps the existing SoC-specific implementations behind a ++ * single driver name and compatible strings. For now we keep the ++ * full implementations in their original files and dispatch through ++ * small per-SoC glue ops. ++ */ + -+ iounmap(ctx->base); -+ release_mem_region(ctx->res_start, ctx->res_size); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ kfree(ctx); -+} ++#include "aspeed-espi.h" ++#include "ast2500-espi.h" ++#include "ast2600-espi.h" ++#include "ast2700-espi.h" + -+static const struct kobj_type aspeed_xdma_kobject_type = { -+ .release = aspeed_xdma_kobject_release, ++struct aspeed_espi_ops { ++ enum aspeed_espi_platform_id platform_id; ++ void (*espi_pre_init)(struct aspeed_espi *espi); ++ void (*espi_post_init)(struct aspeed_espi *espi); ++ void (*espi_deinit)(struct aspeed_espi *espi); ++ int (*espi_perif_probe)(struct aspeed_espi *espi); ++ int (*espi_perif_remove)(struct aspeed_espi *espi); ++ int (*espi_vw_probe)(struct aspeed_espi *espi); ++ int (*espi_vw_remove)(struct aspeed_espi *espi); ++ int (*espi_oob_probe)(struct aspeed_espi *espi); ++ int (*espi_oob_remove)(struct aspeed_espi *espi); ++ int (*espi_flash_probe)(struct aspeed_espi *espi); ++ int (*espi_flash_remove)(struct aspeed_espi *espi); ++ irqreturn_t (*espi_isr)(int irq, void *espi); ++}; ++ ++static const struct aspeed_espi_ops aspeed_espi_ast2500_ops = { ++ .platform_id = ASPEED_ESPI_PLATFORM_ID_AST2500, ++ .espi_pre_init = ast2500_espi_pre_init, ++ .espi_post_init = ast2500_espi_post_init, ++ .espi_deinit = ast2500_espi_deinit, ++ .espi_perif_probe = ast2500_espi_perif_probe, ++ .espi_perif_remove = ast2500_espi_perif_remove, ++ .espi_vw_probe = ast2500_espi_vw_probe, ++ .espi_vw_remove = ast2500_espi_vw_remove, ++ .espi_oob_probe = ast2500_espi_oob_probe, ++ .espi_oob_remove = ast2500_espi_oob_remove, ++ .espi_flash_probe = ast2500_espi_flash_probe, ++ .espi_flash_remove = ast2500_espi_flash_remove, ++ .espi_isr = ast2500_espi_isr, ++}; ++ ++static const struct aspeed_espi_ops aspeed_espi_ast2600_ops = { ++ .platform_id = ASPEED_ESPI_PLATFORM_ID_AST2600, ++ .espi_pre_init = ast2600_espi_pre_init, ++ .espi_post_init = ast2600_espi_post_init, ++ .espi_deinit = ast2600_espi_deinit, ++ .espi_perif_probe = ast2600_espi_perif_probe, ++ .espi_perif_remove = ast2600_espi_perif_remove, ++ .espi_vw_probe = ast2600_espi_vw_probe, ++ .espi_vw_remove = ast2600_espi_vw_remove, ++ .espi_oob_probe = ast2600_espi_oob_probe, ++ .espi_oob_remove = ast2600_espi_oob_remove, ++ .espi_flash_probe = ast2600_espi_flash_probe, ++ .espi_flash_remove = ast2600_espi_flash_remove, ++ .espi_isr = ast2600_espi_isr, ++}; ++ ++static const struct aspeed_espi_ops aspeed_espi_ast2700_ops = { ++ .platform_id = ASPEED_ESPI_PLATFORM_ID_AST2700, ++ .espi_pre_init = ast2700_espi_pre_init, ++ .espi_post_init = ast2700_espi_post_init, ++ .espi_deinit = ast2700_espi_deinit, ++ .espi_perif_probe = ast2700_espi_perif_probe, ++ .espi_perif_remove = ast2700_espi_perif_remove, ++ .espi_vw_probe = ast2700_espi_vw_probe, ++ .espi_vw_remove = ast2700_espi_vw_remove, ++ .espi_oob_probe = ast2700_espi_oob_probe, ++ .espi_oob_remove = ast2700_espi_oob_remove, ++ .espi_flash_probe = ast2700_espi_flash_probe, ++ .espi_flash_remove = ast2700_espi_flash_remove, ++ .espi_isr = ast2700_espi_isr, ++}; ++ ++static const struct of_device_id aspeed_espi_of_matches[] = { ++ { .compatible = "aspeed,ast2500-espi", .data = &aspeed_espi_ast2500_ops }, ++ { .compatible = "aspeed,ast2600-espi", .data = &aspeed_espi_ast2600_ops }, ++ { .compatible = "aspeed,ast2700-espi", .data = &aspeed_espi_ast2700_ops }, ++ { } +}; ++MODULE_DEVICE_TABLE(of, aspeed_espi_of_matches); + -+static int aspeed_xdma_iomap(struct aspeed_xdma *ctx, -+ struct platform_device *pdev) -+{ -+ resource_size_t size; -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ -+ if (!res) -+ return -ENOMEM; -+ -+ size = resource_size(res); -+ if (!request_mem_region(res->start, size, dev_name(ctx->dev))) -+ return -ENOMEM; -+ -+ ctx->base = ioremap(res->start, size); -+ if (!ctx->base) { -+ release_mem_region(res->start, size); -+ return -ENOMEM; -+ } -+ -+ ctx->res_start = res->start; -+ ctx->res_size = size; -+ -+ return 0; -+} -+ -+static int aspeed_xdma_probe(struct platform_device *pdev) ++static int aspeed_espi_probe(struct platform_device *pdev) +{ -+ int rc, id; -+ struct aspeed_xdma *ctx; -+ struct reserved_mem *mem; ++ const struct of_device_id *match; + struct device *dev = &pdev->dev; -+ struct device_node *memory_region; -+ const void *md = of_device_get_match_data(dev); -+ bool rc_f; -+ -+ if (!md) -+ return -ENODEV; ++ struct aspeed_espi *espi; ++ struct resource *res; ++ int rc; + -+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) ++ espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); ++ if (!espi) + return -ENOMEM; + -+ ctx->chip = md; -+ ctx->dev = dev; -+ platform_set_drvdata(pdev, ctx); -+ spin_lock_init(&ctx->client_lock); -+ spin_lock_init(&ctx->engine_lock); -+ INIT_WORK(&ctx->reset_work, aspeed_xdma_reset_work); -+ init_waitqueue_head(&ctx->wait); ++ espi->dev = dev; ++ match = of_match_device(aspeed_espi_of_matches, dev); ++ if (!match) ++ return -ENODEV; ++ espi->ops = match->data; + -+ rc_f = of_find_property(dev->of_node, "pcie_rc", NULL) ? 1 : 0; ++ espi->pdev = pdev; + -+ rc = aspeed_xdma_iomap(ctx, pdev); ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (rc) { -+ dev_err(dev, "Failed to map registers.\n"); -+ goto err_nomap; -+ } -+ -+ ctx->irq = platform_get_irq(pdev, 0); -+ if (ctx->irq < 0) { -+ dev_err(dev, "Failed to find IRQ.\n"); -+ rc = ctx->irq; -+ goto err_noirq; ++ dev_err(dev, "cannot set 64-bits DMA mask\n"); ++ return rc; + } + -+ rc = request_irq(ctx->irq, aspeed_xdma_irq, 0, dev_name(dev), ctx); -+ if (rc < 0) { -+ dev_err(dev, "Failed to request IRQ %d.\n", ctx->irq); -+ goto err_noirq; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(dev, "cannot get resource\n"); ++ return -ENODEV; + } + -+ ctx->clock = clk_get(dev, NULL); -+ if (IS_ERR(ctx->clock)) { -+ dev_err(dev, "Failed to request clock.\n"); -+ rc = PTR_ERR(ctx->clock); -+ goto err_noclk; ++ espi->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(espi->regs)) { ++ dev_err(dev, "cannot map registers\n"); ++ return PTR_ERR(espi->regs); + } + -+ ctx->reset = reset_control_get_exclusive(dev, NULL); -+ if (IS_ERR(ctx->reset)) { -+ dev_err(dev, "Failed to request reset control.\n"); -+ rc = PTR_ERR(ctx->reset); -+ goto err_noreset; ++ espi->irq = platform_get_irq(pdev, 0); ++ if (espi->irq < 0) { ++ dev_err(dev, "cannot get IRQ number\n"); ++ return -ENODEV; + } + -+ if (rc_f) { -+ ctx->reset_rc = reset_control_get_exclusive(dev, "root-complex"); -+ if (IS_ERR(ctx->reset_rc)) { -+ dev_dbg(dev, "Failed to request reset RC control.\n"); -+ ctx->reset_rc = NULL; -+ } ++ espi->rst = devm_reset_control_get_optional(&pdev->dev, NULL); ++ if (IS_ERR(espi->rst)) { ++ dev_err(dev, "cannot get reset control\n"); ++ return PTR_ERR(espi->rst); + } + -+ memory_region = of_parse_phandle(dev->of_node, "memory-region", 0); -+ if (!memory_region) { -+ dev_err(dev, "Failed to find memory-region.\n"); -+ rc = -ENOMEM; -+ goto err_nomem; ++ espi->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(espi->clk)) { ++ dev_err(dev, "cannot get clock control\n"); ++ return PTR_ERR(espi->clk); + } + -+ mem = of_reserved_mem_lookup(memory_region); -+ of_node_put(memory_region); -+ if (!mem) { -+ dev_err(dev, "Failed to find reserved memory.\n"); -+ rc = -ENOMEM; -+ goto err_nomem; ++ rc = clk_prepare_enable(espi->clk); ++ if (rc) { ++ dev_err(dev, "cannot enable clocks\n"); ++ return rc; + } + -+ ctx->mem_phys = mem->base; -+ ctx->mem_size = mem->size; ++ espi->ops->espi_pre_init(espi); + -+ rc = of_reserved_mem_device_init(dev); ++ rc = espi->ops->espi_perif_probe(espi); + if (rc) { -+ dev_err(dev, "Failed to init reserved memory.\n"); -+ goto err_nomem; ++ dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); ++ return rc; + } + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ rc = espi->ops->espi_vw_probe(espi); + if (rc) { -+ dev_err(dev, "Failed to mask DMA.\n"); -+ goto err_nomem; -+ } -+ -+ ctx->mem_virt = dma_alloc_coherent(dev, ctx->mem_size, -+ &ctx->mem_coherent, __GFP_NOWARN); -+ if (!ctx->mem_virt) { -+ dev_err(dev, "Failed to allocate reserved memory.\n"); -+ rc = -ENOMEM; -+ goto err_nomem; ++ dev_err(dev, "cannot init vw channel, rc=%d\n", rc); ++ goto err_remove_perif; + } + -+ ctx->pool = gen_pool_create(ilog2(PAGE_SIZE), -1); -+ if (!ctx->pool) { -+ dev_err(dev, "Failed to setup genalloc pool.\n"); -+ rc = -ENOMEM; -+ goto err_nopool; ++ rc = espi->ops->espi_oob_probe(espi); ++ if (rc) { ++ dev_err(dev, "cannot init oob channel, rc=%d\n", rc); ++ goto err_remove_vw; + } + -+ rc = gen_pool_add_virt(ctx->pool, (unsigned long)ctx->mem_virt, -+ ctx->mem_phys, ctx->mem_size, -1); ++ rc = espi->ops->espi_flash_probe(espi); + if (rc) { -+ dev_err(ctx->dev, "Failed to add memory to genalloc pool.\n"); -+ goto err_pool_scu_clk; ++ dev_err(dev, "cannot init flash channel, rc=%d\n", rc); ++ goto err_remove_oob; + } + -+ rc = aspeed_xdma_init_scu(ctx, dev); -+ if (rc) -+ goto err_pool_scu_clk; -+ -+ rc = clk_prepare_enable(ctx->clock); ++ rc = devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, ++ dev_name(dev), espi); + if (rc) { -+ dev_err(dev, "Failed to enable the clock.\n"); -+ goto err_pool_scu_clk; ++ dev_err(dev, "cannot request IRQ\n"); ++ goto err_remove_flash; + } + -+ if (ctx->reset_rc) { -+ rc = reset_control_deassert(ctx->reset_rc); ++ if (espi->perif.mmbi.enable) { ++ rc = devm_request_irq(dev, espi->perif.mmbi.irq, ++ espi->perif.mmbi.mmbi_isr, 0, dev_name(dev), ++ espi); + if (rc) { -+ dev_err(dev, "Failed to clear the RC reset.\n"); -+ goto err_reset_rc; ++ dev_err(dev, "cannot request MMBI IRQ\n"); ++ goto err_remove_flash; + } -+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, -+ XDMA_ENGINE_SETUP_TIME_MAX_US); -+ } -+ -+ rc = reset_control_deassert(ctx->reset); -+ if (rc) { -+ dev_err(dev, "Failed to clear the reset.\n"); -+ goto err_reset; -+ } -+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US, -+ XDMA_ENGINE_SETUP_TIME_MAX_US); -+ -+ ctx->cmdq = gen_pool_dma_alloc(ctx->pool, XDMA_CMDQ_SIZE, -+ &ctx->cmdq_phys); -+ if (!ctx->cmdq) { -+ dev_err(ctx->dev, "Failed to genalloc cmdq.\n"); -+ rc = -ENOMEM; -+ goto err_pool; + } + -+ aspeed_xdma_init_eng(ctx); -+ -+ id = of_alias_get_id(dev->of_node, "xdma"); -+ if (id < 0) -+ id = 0; ++ espi->ops->espi_post_init(espi); + -+ ctx->misc.minor = MISC_DYNAMIC_MINOR; -+ ctx->misc.fops = &aspeed_xdma_fops; -+ ctx->misc.name = kasprintf(GFP_KERNEL, "%s%d", DEVICE_NAME, id); -+ ctx->misc.parent = dev; -+ rc = misc_register(&ctx->misc); -+ if (rc) { -+ dev_err(dev, "Failed to register xdma miscdevice.\n"); -+ goto err_misc; -+ } ++ platform_set_drvdata(pdev, espi); + -+ /* -+ * This interrupt could fire immediately so only request it once the -+ * engine and driver are initialized. -+ */ -+ ctx->pcie_irq = platform_get_irq(pdev, 1); -+ if (ctx->pcie_irq < 0) { -+ dev_warn(dev, "Failed to find PCI-E IRQ.\n"); -+ } else { -+ rc = request_irq(ctx->pcie_irq, aspeed_xdma_pcie_irq, -+ IRQF_SHARED, dev_name(dev), ctx); -+ if (rc < 0) { -+ dev_warn(dev, "Failed to request PCI-E IRQ %d.\n", rc); -+ ctx->pcie_irq = -1; -+ } -+ } ++ dev_info(dev, "module loaded\n"); + -+ kobject_init(&ctx->kobj, &aspeed_xdma_kobject_type); + return 0; + -+err_misc: -+ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE); -+err_pool: -+ reset_control_assert(ctx->reset); -+err_reset: -+ if (ctx->reset_rc) -+ reset_control_assert(ctx->reset_rc); -+err_reset_rc: -+ clk_disable_unprepare(ctx->clock); -+err_pool_scu_clk: -+ gen_pool_destroy(ctx->pool); -+err_nopool: -+ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt, -+ ctx->mem_coherent); -+err_nomem: -+ if (ctx->reset_rc) -+ reset_control_put(ctx->reset_rc); -+ reset_control_put(ctx->reset); -+err_noreset: -+ clk_put(ctx->clock); -+err_noclk: -+ free_irq(ctx->irq, ctx); -+err_noirq: -+ iounmap(ctx->base); -+ release_mem_region(ctx->res_start, ctx->res_size); -+err_nomap: -+ kfree(ctx); ++err_remove_flash: ++ espi->ops->espi_flash_remove(espi); ++err_remove_oob: ++ espi->ops->espi_oob_remove(espi); ++err_remove_vw: ++ espi->ops->espi_vw_remove(espi); ++err_remove_perif: ++ espi->ops->espi_perif_remove(espi); ++ + return rc; +} + -+static void aspeed_xdma_remove(struct platform_device *pdev) ++static void aspeed_espi_remove(struct platform_device *pdev) +{ -+ struct aspeed_xdma *ctx = platform_get_drvdata(pdev); -+ -+ reset_control_assert(ctx->reset); -+ if (ctx->reset_rc) -+ reset_control_assert(ctx->reset_rc); -+ clk_disable_unprepare(ctx->clock); -+ -+ aspeed_xdma_done(ctx, true); -+ -+ misc_deregister(&ctx->misc); -+ kobject_put(&ctx->kobj); -+} -+ -+static const struct aspeed_xdma_chip aspeed_ast2500_xdma_chip = { -+ .control = XDMA_AST2500_CTRL_US_COMP | XDMA_AST2500_CTRL_DS_COMP | -+ XDMA_AST2500_CTRL_DS_DIRTY | XDMA_AST2500_CTRL_DS_SIZE_256 | -+ XDMA_AST2500_CTRL_DS_TIMEOUT | XDMA_AST2500_CTRL_DS_CHECK_ID, -+ .scu_bmc_class = SCU_AST2500_BMC_CLASS_REV, -+ .scu_misc_ctrl = 0, -+ .scu_pcie_conf = SCU_AST2500_PCIE_CONF, -+ .scu_pcie_ctrl = 0, -+ .queue_entry_size = XDMA_AST2500_QUEUE_ENTRY_SIZE, -+ .regs = { -+ .bmc_cmdq_addr = XDMA_AST2500_BMC_CMDQ_ADDR, -+ .bmc_cmdq_addr_ext = 0, -+ .bmc_cmdq_endp = XDMA_AST2500_BMC_CMDQ_ENDP, -+ .bmc_cmdq_writep = XDMA_AST2500_BMC_CMDQ_WRITEP, -+ .bmc_cmdq_readp = XDMA_AST2500_BMC_CMDQ_READP, -+ .control = XDMA_AST2500_CTRL, -+ .status = XDMA_AST2500_STATUS, -+ }, -+ .status_bits = { -+ .us_comp = XDMA_AST2500_STATUS_US_COMP, -+ .ds_comp = XDMA_AST2500_STATUS_DS_COMP, -+ .ds_dirty = XDMA_AST2500_STATUS_DS_DIRTY, -+ }, -+ .set_cmd = aspeed_xdma_ast2500_set_cmd, -+}; ++ struct aspeed_espi *espi; ++ struct device *dev; + -+static const struct aspeed_xdma_chip aspeed_ast2600_xdma_chip = { -+ .control = XDMA_AST2600_CTRL_US_COMP | XDMA_AST2600_CTRL_DS_COMP | -+ XDMA_AST2600_CTRL_DS_DIRTY | XDMA_AST2600_CTRL_DS_SIZE_256, -+ .scu_bmc_class = SCU_AST2600_BMC_CLASS_REV, -+ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL, -+ .scu_misc_mask = SCU_AST2600_MISC_CTRL_XDMA_BMC, -+ .scu_disable_mask = DEBUG_CTRL_AST2600_XDMA_DISABLE, -+ .scu_pcie_conf = SCU_AST2600_PCIE_CONF, -+ .scu_pcie_ctrl = 0, -+ .queue_entry_size = XDMA_AST2600_QUEUE_ENTRY_SIZE, -+ .regs = { -+ .bmc_cmdq_addr = XDMA_AST2600_BMC_CMDQ_ADDR, -+ .bmc_cmdq_addr_ext = 0, -+ .bmc_cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP, -+ .bmc_cmdq_writep = XDMA_AST2600_BMC_CMDQ_WRITEP, -+ .bmc_cmdq_readp = XDMA_AST2600_BMC_CMDQ_READP, -+ .control = XDMA_AST2600_CTRL, -+ .status = XDMA_AST2600_STATUS, -+ }, -+ .status_bits = { -+ .us_comp = XDMA_AST2600_STATUS_US_COMP, -+ .ds_comp = XDMA_AST2600_STATUS_DS_COMP, -+ .ds_dirty = XDMA_AST2600_STATUS_DS_DIRTY, -+ }, -+ .set_cmd = aspeed_xdma_ast2600_set_cmd, -+}; ++ dev = &pdev->dev; + -+static const struct aspeed_xdma_chip aspeed_ast2700_xdma0_chip = { -+ .control = XDMA_AST2700_CTRL_US_COMP | XDMA_AST2700_CTRL_DS_COMP | -+ XDMA_AST2700_CTRL_DS_DIRTY, -+ .scu_bmc_class = SCU_AST2700_PCIE0_BMC_CLASS_REV, -+ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL, -+ .scu_misc_mask = SCU_AST2700_MISC_CTRL_XDMA_CLIENT, -+ .scu_disable_mask = DEBUG_CTRL_AST2600_XDMA_DISABLE | DEBUG_CTRL_AST2700_XDMA_DISABLE, -+ .scu_pcie_conf = SCU_AST2700_PCIE0_CONF, -+ .scu_pcie_ctrl = SCU_AST2700_PCIE0_CTRL, -+ .queue_entry_size = XDMA_AST2700_QUEUE_ENTRY_SIZE, -+ .regs = { -+ .bmc_cmdq_addr = XDMA_AST2700_BMC_CMDQ_ADDR0, -+ .bmc_cmdq_addr_ext = XDMA_AST2700_BMC_CMDQ_ADDR1, -+ .bmc_cmdq_endp = XDMA_AST2700_BMC_CMDQ_ENDP, -+ .bmc_cmdq_writep = XDMA_AST2700_BMC_CMDQ_WRITEP, -+ .bmc_cmdq_readp = XDMA_AST2700_BMC_CMDQ_READP, -+ .control = XDMA_AST2700_CTRL, -+ .status = XDMA_AST2700_STATUS, -+ }, -+ .status_bits = { -+ .us_comp = XDMA_AST2700_STATUS_US_COMP, -+ .ds_comp = XDMA_AST2700_STATUS_DS_COMP, -+ .ds_dirty = XDMA_AST2700_STATUS_DS_DIRTY, -+ }, -+ .set_cmd = aspeed_xdma_ast2700_set_cmd, -+}; ++ espi = dev_get_drvdata(dev); + -+static const struct aspeed_xdma_chip aspeed_ast2700_xdma1_chip = { -+ .control = XDMA_AST2700_CTRL_US_COMP | XDMA_AST2700_CTRL_DS_COMP | -+ XDMA_AST2700_CTRL_DS_DIRTY, -+ .scu_bmc_class = SCU_AST2700_PCIE1_BMC_CLASS_REV, -+ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL, -+ .scu_misc_mask = SCU_AST2700_MISC_CTRL_XDMA_CLIENT, -+ .scu_disable_mask = DEBUG_CTRL_AST2600_XDMA_DISABLE | DEBUG_CTRL_AST2700_XDMA_DISABLE, -+ .scu_pcie_conf = SCU_AST2700_PCIE1_CONF, -+ .scu_pcie_ctrl = SCU_AST2700_PCIE1_CTRL, -+ .queue_entry_size = XDMA_AST2700_QUEUE_ENTRY_SIZE, -+ .regs = { -+ .bmc_cmdq_addr = XDMA_AST2700_BMC_CMDQ_ADDR0, -+ .bmc_cmdq_addr_ext = XDMA_AST2700_BMC_CMDQ_ADDR1, -+ .bmc_cmdq_endp = XDMA_AST2700_BMC_CMDQ_ENDP, -+ .bmc_cmdq_writep = XDMA_AST2700_BMC_CMDQ_WRITEP, -+ .bmc_cmdq_readp = XDMA_AST2700_BMC_CMDQ_READP, -+ .control = XDMA_AST2700_CTRL, -+ .status = XDMA_AST2700_STATUS, -+ }, -+ .status_bits = { -+ .us_comp = XDMA_AST2700_STATUS_US_COMP, -+ .ds_comp = XDMA_AST2700_STATUS_DS_COMP, -+ .ds_dirty = XDMA_AST2700_STATUS_DS_DIRTY, -+ }, -+ .set_cmd = aspeed_xdma_ast2700_set_cmd, -+}; ++ espi->ops->espi_deinit(espi); + -+static const struct of_device_id aspeed_xdma_match[] = { -+ { -+ .compatible = "aspeed,ast2500-xdma", -+ .data = &aspeed_ast2500_xdma_chip, -+ }, -+ { -+ .compatible = "aspeed,ast2600-xdma", -+ .data = &aspeed_ast2600_xdma_chip, -+ }, -+ { -+ .compatible = "aspeed,ast2700-xdma0", -+ .data = &aspeed_ast2700_xdma0_chip, -+ }, -+ { -+ .compatible = "aspeed,ast2700-xdma1", -+ .data = &aspeed_ast2700_xdma1_chip, -+ }, -+ { }, -+}; ++ if (espi->ops->espi_perif_remove(espi)) ++ dev_warn(dev, "cannot remove peripheral channel\n"); ++ if (espi->ops->espi_vw_remove(espi)) ++ dev_warn(dev, "cannot remove vw channel\n"); ++ if (espi->ops->espi_oob_remove(espi)) ++ dev_warn(dev, "cannot remove oob channel\n"); ++ if (espi->ops->espi_flash_remove(espi)) ++ dev_warn(dev, "cannot remove flash channel\n"); ++} + -+static struct platform_driver aspeed_xdma_driver = { -+ .probe = aspeed_xdma_probe, -+ .remove = aspeed_xdma_remove, ++static struct platform_driver aspeed_espi_driver = { + .driver = { -+ .name = DEVICE_NAME, -+ .of_match_table = aspeed_xdma_match, ++ .name = "aspeed-espi", ++ .of_match_table = aspeed_espi_of_matches, + }, ++ .probe = aspeed_espi_probe, ++ .remove = aspeed_espi_remove, +}; + -+module_platform_driver(aspeed_xdma_driver); ++module_platform_driver(aspeed_espi_driver); + -+MODULE_AUTHOR("Eddie James"); -+MODULE_DESCRIPTION("ASPEED XDMA Engine Driver"); ++MODULE_AUTHOR("Aspeed Technology Inc."); ++MODULE_DESCRIPTION("Aspeed eSPI controller (AST2500/2600/2700)"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi.c ---- a/drivers/soc/aspeed/ast2500-espi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2500-espi.c 2025-12-23 10:16:21.125032653 +0000 -@@ -0,0 +1,1739 @@ -+// SPDX-License-Identifier: GPL-2.0+ +diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/espi/aspeed-espi.h +--- a/drivers/soc/aspeed/espi/aspeed-espi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/aspeed-espi.h 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,231 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ +/* -+ * Copyright 2023 Aspeed Technology Inc. ++ * Unified eSPI driver header file and data structures ++ * Copyright 2026 Aspeed Technology Inc. + */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++#ifndef __ASPEED_ESPI_H__ ++#define __ASPEED_ESPI_H__ + -+#include "ast2500-espi.h" ++#include "linux/platform_device.h" ++#include ++#include ++#include + ++#define PERIF_MMBI_INST_NUM 8 +#define DEVICE_NAME "aspeed-espi" + -+#define PERIF_MCYC_UNLOCK 0xfedc756e -+#define PERIF_MCYC_ALIGN SZ_64K ++enum aspeed_espi_platform_id { ++ ASPEED_ESPI_PLATFORM_ID_AST2500 = 0x2500, ++ ASPEED_ESPI_PLATFORM_ID_AST2600 = 0x2600, ++ ASPEED_ESPI_PLATFORM_ID_AST2700 = 0x2700, ++}; + -+#define FLASH_SAFS_ALIGN SZ_16M ++/* consistent with DTS property "flash-safs-mode" */ ++enum aspeed_edaf_mode { ++ EDAF_MODE_MIX = 0x0, ++ EDAF_MODE_SW, ++ EDAF_MODE_HW, ++ EDAF_MODES, ++}; ++ ++struct aspeed_espi_perif; ++ ++struct aspeed_espi_perif_mmbi { ++ void *b2h_virt; ++ void *h2b_virt; ++ dma_addr_t b2h_addr; ++ dma_addr_t h2b_addr; ++ struct miscdevice b2h_mdev; ++ struct miscdevice h2b_mdev; ++ bool host_rwp_update; ++ wait_queue_head_t wq; ++ struct aspeed_espi_perif *perif; ++}; ++ ++struct aspeed_espi_perif { ++ struct { ++ bool enable; ++ int irq; ++ void *virt; ++ dma_addr_t taddr; ++ dma_addr_t saddr; ++ resource_size_t size; ++ u32 inst_num; ++ u32 inst_size; ++ irqreturn_t (*mmbi_isr)(int irq, void *espi); ++ struct aspeed_espi_perif_mmbi inst[PERIF_MMBI_INST_NUM]; ++ } mmbi; + -+struct ast2500_espi_perif { + struct { + bool enable; + void *virt; + dma_addr_t taddr; -+ uint32_t saddr; -+ uint32_t size; ++ dma_addr_t saddr; ++ resource_size_t size; + } mcyc; + + struct { @@ -66746,29 +66866,103 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + dma_addr_t pc_rx_addr; + } dma; + ++ bool rtc_enable; + bool rx_ready; + wait_queue_head_t wq; + -+ spinlock_t lock; -+ struct mutex np_tx_mtx; -+ struct mutex pc_tx_mtx; -+ struct mutex pc_rx_mtx; ++ spinlock_t lock; // protects rx_ready ++ struct mutex np_tx_mtx; // protects np_tx_virt/addr ++ struct mutex pc_tx_mtx; // protects pc_tx_virt/addr ++ struct mutex pc_rx_mtx; // protects pc_rx_virt/addr + + struct miscdevice mdev; +}; + -+struct ast2500_espi_vw { ++struct aspeed_espi_vw { + struct { + bool hw_mode; -+ uint32_t val; ++ u32 grp; ++ u32 dir0; ++ u32 dir1; ++ u32 val0; ++ u32 val1; + } gpio; + ++ struct { ++ u8 pch_generic; ++ } platform; ++ ++ struct { ++ bool enabled; ++ spinlock_t pltrst_lock; // protects pltrst_status ++ wait_queue_head_t pltrst_wq; ++ char pltrst_status; ++ bool pltrst_avail; ++ } pltrst; ++ ++ struct miscdevice pltrst_mdev; + struct miscdevice mdev; +}; + -+struct ast2500_espi_oob { ++struct ast2700_espi_oob_dma_tx_desc { ++ u32 data_addrl; ++ u32 data_addrh; ++ u8 cyc; ++ u16 tag : 4; ++ u16 len : 12; ++ u8 msg_type : 3; ++ u8 raz0 : 1; ++ u8 pec : 1; ++ u8 int_en : 1; ++ u8 pause : 1; ++ u8 raz1 : 1; ++ u32 raz2; ++ u32 raz3; ++ u32 pad[3]; ++} __packed; ++ ++struct ast2700_espi_oob_dma_rx_desc { ++ u32 data_addrl; ++ u32 data_addrh; ++ u8 cyc; ++ u16 tag : 4; ++ u16 len : 12; ++ u8 raz : 7; ++ u8 dirty : 1; ++ u32 pad; ++} __packed; ++ ++struct ast2600_espi_oob_dma_tx_desc { ++ u32 data_addr; ++ u8 cyc; ++ u16 tag : 4; ++ u16 len : 12; ++ u8 msg_type : 3; ++ u8 raz0 : 1; ++ u8 pec : 1; ++ u8 int_en : 1; ++ u8 pause : 1; ++ u8 raz1 : 1; ++ u32 raz2; ++ u32 raz3; ++} __packed; ++ ++struct ast2600_espi_oob_dma_rx_desc { ++ u32 data_addr; ++ u8 cyc; ++ u16 tag : 4; ++ u16 len : 12; ++ u8 raz : 7; ++ u8 dirty : 1; ++} __packed; ++ ++struct aspeed_espi_oob { + struct { + bool enable; ++ void *txd_virt; ++ dma_addr_t txd_addr; ++ void *rxd_virt; ++ dma_addr_t rxd_addr; + void *tx_virt; + dma_addr_t tx_addr; + void *rx_virt; @@ -66778,19 +66972,19 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + bool rx_ready; + wait_queue_head_t wq; + -+ spinlock_t lock; -+ struct mutex tx_mtx; -+ struct mutex rx_mtx; ++ spinlock_t lock; // protects rx_ready ++ struct mutex tx_mtx; // protects tx_virt/addr ++ struct mutex rx_mtx; // protects rx_virt/addr + + struct miscdevice mdev; +}; + -+struct ast2500_espi_flash { ++struct aspeed_espi_flash { + struct { -+ uint32_t mode; ++ u32 mode; + phys_addr_t taddr; -+ uint32_t size; -+ } safs; ++ resource_size_t size; ++ } edaf; + + struct { + bool enable; @@ -66803,39 +66997,78 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + bool rx_ready; + wait_queue_head_t wq; + -+ spinlock_t lock; -+ struct mutex rx_mtx; -+ struct mutex tx_mtx; ++ spinlock_t lock; // protects rx_ready ++ struct mutex rx_mtx; // protects rx_virt/addr ++ struct mutex tx_mtx; // protects tx_virt/addr + + struct miscdevice mdev; +}; + -+struct ast2500_espi { ++struct aspeed_espi { ++ struct platform_device *pdev; + struct device *dev; + void __iomem *regs; ++ struct reset_control *rst; + struct clk *clk; ++ int dev_id; + int irq; + -+ struct ast2500_espi_perif perif; -+ struct ast2500_espi_vw vw; -+ struct ast2500_espi_oob oob; -+ struct ast2500_espi_flash flash; ++ struct aspeed_espi_perif perif; ++ struct aspeed_espi_vw vw; ++ struct aspeed_espi_oob oob; ++ struct aspeed_espi_flash flash; ++ const struct aspeed_espi_ops *ops; +}; + ++#endif // __ASPEED_ESPI_H__ +diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/ast2500-espi.c +--- a/drivers/soc/aspeed/espi/ast2500-espi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2500-espi.c 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,1510 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ast2500-espi.h" ++#include "aspeed-espi-comm.h" ++#include "aspeed-espi.h" ++ ++#define PERIF_MCYC_UNLOCK 0xfedc756e ++#define PERIF_MCYC_ALIGN SZ_64K ++ ++#define FLASH_SAFS_ALIGN SZ_16M ++ +/* peripheral channel (CH0) */ +static long ast2500_espi_perif_pc_get_rx(struct file *fp, -+ struct ast2500_espi_perif *perif, ++ struct aspeed_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; ++ u32 pkt_len; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(perif, struct ast2500_espi, perif); ++ espi = container_of(perif, struct aspeed_espi, perif); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&perif->pc_rx_mtx)) @@ -66943,16 +67176,16 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi +} + +static long ast2500_espi_perif_pc_put_tx(struct file *fp, -+ struct ast2500_espi_perif *perif, ++ struct aspeed_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(perif, struct ast2500_espi, perif); ++ espi = container_of(perif, struct aspeed_espi, perif); + + if (!mutex_trylock(&perif->pc_tx_mtx)) + return -EAGAIN; @@ -67010,16 +67243,16 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi +} + +static long ast2500_espi_perif_np_put_tx(struct file *fp, -+ struct ast2500_espi_perif *perif, ++ struct aspeed_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(perif, struct ast2500_espi, perif); ++ espi = container_of(perif, struct aspeed_espi, perif); + + if (!mutex_trylock(&perif->np_tx_mtx)) + return -EAGAIN; @@ -67078,10 +67311,10 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + +static long ast2500_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2500_espi_perif *perif; ++ struct aspeed_espi_perif *perif; + struct aspeed_espi_ioc ioc; + -+ perif = container_of(fp->private_data, struct ast2500_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -67105,11 +67338,11 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + +static int ast2500_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct ast2500_espi_perif *perif; ++ struct aspeed_espi_perif *perif; + unsigned long vm_size; + pgprot_t vm_prot; + -+ perif = container_of(fp->private_data, struct ast2500_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); + if (!perif->mcyc.enable) + return -EPERM; + @@ -67135,11 +67368,11 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + .unlocked_ioctl = ast2500_espi_perif_ioctl, +}; + -+static void ast2500_espi_perif_isr(struct ast2500_espi *espi) ++static void ast2500_espi_perif_isr(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_perif *perif; ++ struct aspeed_espi_perif *perif; + unsigned long flags; -+ uint32_t sts; ++ u32 sts; + + perif = &espi->perif; + @@ -67156,11 +67389,11 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + } +} + -+static void ast2500_espi_perif_reset(struct ast2500_espi *espi) ++static void ast2500_espi_perif_reset(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_perif *perif; ++ struct aspeed_espi_perif *perif; + struct device *dev; -+ uint32_t reg, mask; ++ u32 reg, mask; + + dev = espi->dev; + @@ -67218,9 +67451,9 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + writel(reg, espi->regs + ESPI_CTRL); +} + -+static int ast2500_espi_perif_probe(struct ast2500_espi *espi) ++int ast2500_espi_perif_probe(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_perif *perif; ++ struct aspeed_espi_perif *perif; + struct device *dev; + int rc; + @@ -67238,13 +67471,13 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + + perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); + if (perif->mcyc.enable) { -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", &perif->mcyc.saddr); ++ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", (u32 *)&perif->mcyc.saddr); + if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { + dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); + return -ENODEV; + } + -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", &perif->mcyc.size); ++ rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", (u32 *)&perif->mcyc.size); + if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { + dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); + return -EINVAL; @@ -67297,11 +67530,11 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + return 0; +} + -+static int ast2500_espi_perif_remove(struct ast2500_espi *espi) ++int ast2500_espi_perif_remove(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_perif *perif; ++ struct aspeed_espi_perif *perif; + struct device *dev; -+ uint32_t reg; ++ u32 reg; + + dev = espi->dev; + @@ -67343,21 +67576,21 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi +/* virtual wire channel (CH1) */ +static long ast2500_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2500_espi_vw *vw; -+ struct ast2500_espi *espi; -+ uint32_t gpio; ++ struct aspeed_espi_vw *vw; ++ struct aspeed_espi *espi; ++ u32 gpio; + -+ vw = container_of(fp->private_data, struct ast2500_espi_vw, mdev); -+ espi = container_of(vw, struct ast2500_espi, vw); -+ gpio = vw->gpio.val; ++ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); ++ espi = container_of(vw, struct aspeed_espi, vw); ++ gpio = vw->gpio.val0; + + switch (cmd) { + case ASPEED_ESPI_VW_GET_GPIO_VAL: -+ if (put_user(gpio, (uint32_t __user *)arg)) ++ if (put_user(gpio, (u32 __user *)arg)) + return -EFAULT; + break; + case ASPEED_ESPI_VW_PUT_GPIO_VAL: -+ if (get_user(gpio, (uint32_t __user *)arg)) ++ if (get_user(gpio, (u32 __user *)arg)) + return -EFAULT; + + writel(gpio, espi->regs + ESPI_VW_GPIO_VAL); @@ -67374,10 +67607,10 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + .unlocked_ioctl = ast2500_espi_vw_ioctl, +}; + -+static void ast2500_espi_vw_isr(struct ast2500_espi *espi) ++static void ast2500_espi_vw_isr(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_vw *vw; -+ uint32_t reg, sts, sts_sysevt; ++ struct aspeed_espi_vw *vw; ++ u32 reg, sts, sts_sysevt; + + vw = &espi->vw; + @@ -67414,22 +67647,22 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + } + + if (sts & ESPI_INT_STS_VW_GPIO) { -+ vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); + writel(ESPI_INT_STS_VW_GPIO, espi->regs + ESPI_INT_STS); + } +} + -+static void ast2500_espi_vw_reset(struct ast2500_espi *espi) ++static void ast2500_espi_vw_reset(struct aspeed_espi *espi) +{ -+ uint32_t reg; -+ struct ast2500_espi_vw *vw = &espi->vw; ++ u32 reg; ++ struct aspeed_espi_vw *vw = &espi->vw; + + reg = readl(espi->regs + ESPI_INT_EN); + reg &= ~(ESPI_INT_EN_VW); + writel(reg, espi->regs + ESPI_INT_EN); + writel(ESPI_INT_STS_VW, espi->regs + ESPI_INT_STS); + -+ vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); + + /* Host Reset Warn and OOB Reset Warn system events */ + reg = readl(espi->regs + ESPI_VW_SYSEVT_INT_T2) @@ -67466,11 +67699,11 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + writel(reg, espi->regs + ESPI_CTRL); +} + -+static int ast2500_espi_vw_probe(struct ast2500_espi *espi) ++int ast2500_espi_vw_probe(struct aspeed_espi *espi) +{ + int rc; + struct device *dev = espi->dev; -+ struct ast2500_espi_vw *vw = &espi->vw; ++ struct aspeed_espi_vw *vw = &espi->vw; + + writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_EN); + writel(0xffffffff, espi->regs + ESPI_VW_SYSEVT_INT_STS); @@ -67495,10 +67728,10 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + return 0; +} + -+static int ast2500_espi_vw_remove(struct ast2500_espi *espi) ++int ast2500_espi_vw_remove(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_vw *vw; -+ uint32_t reg; ++ struct aspeed_espi_vw *vw; ++ u32 reg; + + vw = &espi->vw; + @@ -67513,18 +67746,18 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + +/* out-of-band channel (CH2) */ +static long ast2500_espi_oob_get_rx(struct file *fp, -+ struct ast2500_espi_oob *oob, ++ struct aspeed_espi_oob *oob, + struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; ++ u32 pkt_len; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(oob, struct ast2500_espi, oob); ++ espi = container_of(oob, struct aspeed_espi, oob); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&oob->rx_mtx)) @@ -67610,16 +67843,16 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi +} + +static long ast2500_espi_oob_put_tx(struct file *fp, -+ struct ast2500_espi_oob *oob, ++ struct aspeed_espi_oob *oob, + struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(oob, struct ast2500_espi, oob); ++ espi = container_of(oob, struct aspeed_espi, oob); + + if (!mutex_trylock(&oob->tx_mtx)) + return -EAGAIN; @@ -67657,18 +67890,381 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + dma_wmb(); + } else { + for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_OOB_TX_DATA); ++ writel(pkt[i], espi->regs + ESPI_OOB_TX_DATA); ++ } ++ ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ ++ reg = FIELD_PREP(ESPI_OOB_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_OOB_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_OOB_TX_CTRL_LEN, len) ++ | ESPI_OOB_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_OOB_TX_CTRL); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++unlock_mtx_n_out: ++ mutex_unlock(&oob->tx_mtx); ++ ++ return rc; ++} ++ ++static long ast2500_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ struct aspeed_espi_oob *oob; ++ struct aspeed_espi_ioc ioc; ++ ++ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); ++ ++ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) ++ return -EFAULT; ++ ++ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case ASPEED_ESPI_OOB_GET_RX: ++ return ast2500_espi_oob_get_rx(fp, oob, &ioc); ++ case ASPEED_ESPI_OOB_PUT_TX: ++ return ast2500_espi_oob_put_tx(fp, oob, &ioc); ++ default: ++ break; ++ }; ++ ++ return -EINVAL; ++} ++ ++static const struct file_operations ast2500_espi_oob_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2500_espi_oob_ioctl, ++}; ++ ++static void ast2500_espi_oob_isr(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_oob *oob; ++ unsigned long flags; ++ u32 sts; ++ ++ oob = &espi->oob; ++ ++ sts = readl(espi->regs + ESPI_INT_STS); ++ ++ if (sts & ESPI_INT_STS_OOB_RX_CMPLT) { ++ writel(ESPI_INT_STS_OOB_RX_CMPLT, espi->regs + ESPI_INT_STS); ++ ++ spin_lock_irqsave(&oob->lock, flags); ++ oob->rx_ready = true; ++ spin_unlock_irqrestore(&oob->lock, flags); ++ ++ wake_up_interruptible(&oob->wq); ++ } ++} ++ ++static void ast2500_espi_oob_reset(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_oob *oob; ++ u32 reg; ++ ++ oob = &espi->oob; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~(ESPI_INT_EN_OOB); ++ writel(reg, espi->regs + ESPI_INT_EN); ++ writel(ESPI_INT_STS_OOB, espi->regs + ESPI_INT_STS); ++ ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_OOB_TX_SW_RST ++ | ESPI_CTRL_OOB_RX_SW_RST ++ | ESPI_CTRL_OOB_TX_DMA_EN ++ | ESPI_CTRL_OOB_RX_DMA_EN ++ | ESPI_CTRL_OOB_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ udelay(1); ++ ++ reg |= (ESPI_CTRL_OOB_TX_SW_RST | ESPI_CTRL_OOB_RX_SW_RST); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ if (oob->dma.enable) { ++ writel(oob->dma.tx_addr, espi->regs + ESPI_OOB_TX_DMA); ++ writel(oob->dma.rx_addr, espi->regs + ESPI_OOB_RX_DMA); ++ ++ reg = readl(espi->regs + ESPI_CTRL) ++ | ESPI_CTRL_OOB_TX_DMA_EN ++ | ESPI_CTRL_OOB_RX_DMA_EN; ++ writel(reg, espi->regs + ESPI_CTRL); ++ } ++ ++ reg = readl(espi->regs + ESPI_INT_EN) | ESPI_INT_EN_OOB_RX_CMPLT; ++ writel(reg, espi->regs + ESPI_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_OOB_SW_RDY; ++ writel(reg, espi->regs + ESPI_CTRL); ++} ++ ++int ast2500_espi_oob_probe(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_oob *oob; ++ struct device *dev; ++ int rc; ++ ++ dev = espi->dev; ++ ++ oob = &espi->oob; ++ ++ init_waitqueue_head(&oob->wq); ++ ++ spin_lock_init(&oob->lock); ++ ++ mutex_init(&oob->tx_mtx); ++ mutex_init(&oob->rx_mtx); ++ ++ oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); ++ if (oob->dma.enable) { ++ oob->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &oob->dma.tx_addr, GFP_KERNEL); ++ if (!oob->dma.tx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } ++ ++ oob->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &oob->dma.rx_addr, GFP_KERNEL); ++ if (!oob->dma.rx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } ++ } ++ ++ oob->mdev.parent = dev; ++ oob->mdev.minor = MISC_DYNAMIC_MINOR; ++ oob->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-oob", DEVICE_NAME); ++ oob->mdev.fops = &ast2500_espi_oob_fops; ++ rc = misc_register(&oob->mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", oob->mdev.name); ++ return rc; ++ } ++ ++ ast2500_espi_oob_reset(espi); ++ ++ return 0; ++} ++ ++int ast2500_espi_oob_remove(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_oob *oob; ++ struct device *dev; ++ u32 reg; ++ ++ dev = espi->dev; ++ ++ oob = &espi->oob; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~(ESPI_INT_EN_OOB); ++ writel(reg, espi->regs + ESPI_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_OOB_TX_DMA_EN ++ | ESPI_CTRL_OOB_RX_DMA_EN ++ | ESPI_CTRL_OOB_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ if (oob->dma.enable) { ++ dmam_free_coherent(dev, PAGE_SIZE, oob->dma.tx_virt, oob->dma.tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, oob->dma.rx_virt, oob->dma.rx_addr); ++ } ++ ++ mutex_destroy(&oob->tx_mtx); ++ mutex_destroy(&oob->rx_mtx); ++ ++ misc_deregister(&oob->mdev); ++ ++ return 0; ++} ++ ++/* flash channel (CH3) */ ++static long ast2500_espi_flash_get_rx(struct file *fp, ++ struct aspeed_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) ++{ ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ unsigned long flags; ++ u32 pkt_len; ++ u8 *pkt; ++ int i, rc; ++ ++ rc = 0; ++ ++ espi = container_of(flash, struct aspeed_espi, flash); ++ ++ if (fp->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&flash->rx_mtx)) ++ return -EAGAIN; ++ ++ if (!flash->rx_ready) { ++ rc = -ENODATA; ++ goto unlock_mtx_n_out; ++ } ++ } else { ++ mutex_lock(&flash->rx_mtx); ++ ++ if (!flash->rx_ready) { ++ rc = wait_event_interruptible(flash->wq, flash->rx_ready); ++ if (rc == -ERESTARTSYS) { ++ rc = -EINTR; ++ goto unlock_mtx_n_out; ++ } ++ } ++ } ++ ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ reg = readl(espi->regs + ESPI_FLASH_RX_CTRL); ++ cyc = FIELD_GET(ESPI_FLASH_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_FLASH_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_FLASH_RX_CTRL_LEN, reg); ++ ++ /* ++ * calculate the length of the rest part of the ++ * eSPI packet to be read from HW and copied to ++ * user space. ++ */ ++ switch (cyc) { ++ case ESPI_FLASH_WRITE: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_flash_rwe); ++ break; ++ case ESPI_FLASH_READ: ++ case ESPI_FLASH_ERASE: ++ pkt_len = sizeof(struct espi_flash_rwe); ++ break; ++ case ESPI_FLASH_SUC_CMPLT_D_MIDDLE: ++ case ESPI_FLASH_SUC_CMPLT_D_FIRST: ++ case ESPI_FLASH_SUC_CMPLT_D_LAST: ++ case ESPI_FLASH_SUC_CMPLT_D_ONLY: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_flash_cmplt); ++ break; ++ case ESPI_FLASH_SUC_CMPLT: ++ case ESPI_FLASH_UNSUC_CMPLT: ++ pkt_len = sizeof(struct espi_flash_cmplt); ++ break; ++ default: ++ rc = -EFAULT; ++ goto unlock_mtx_n_out; ++ } ++ ++ if (ioc->pkt_len < pkt_len) { ++ rc = -EINVAL; ++ goto unlock_mtx_n_out; ++ } ++ ++ pkt = vmalloc(pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; ++ } ++ ++ hdr = (struct espi_comm_hdr *)pkt; ++ hdr->cyc = cyc; ++ hdr->tag = tag; ++ hdr->len_h = len >> 8; ++ hdr->len_l = len & 0xff; ++ ++ if (flash->dma.enable) { ++ memcpy(hdr + 1, flash->dma.rx_virt, pkt_len - sizeof(*hdr)); ++ } else { ++ for (i = sizeof(*hdr); i < pkt_len; ++i) ++ pkt[i] = readl(espi->regs + ESPI_FLASH_RX_DATA) & 0xff; ++ } ++ ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } ++ ++ spin_lock_irqsave(&flash->lock, flags); ++ ++ writel(ESPI_FLASH_RX_CTRL_SERV_PEND, espi->regs + ESPI_FLASH_RX_CTRL); ++ flash->rx_ready = 0; ++ ++ spin_unlock_irqrestore(&flash->lock, flags); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++unlock_mtx_n_out: ++ mutex_unlock(&flash->rx_mtx); ++ ++ return rc; ++} ++ ++static long ast2500_espi_flash_put_tx(struct file *fp, ++ struct aspeed_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) ++{ ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u8 *pkt; ++ int i, rc; ++ ++ espi = container_of(flash, struct aspeed_espi, flash); ++ ++ if (!mutex_trylock(&flash->tx_mtx)) ++ return -EAGAIN; ++ ++ reg = readl(espi->regs + ESPI_FLASH_TX_CTRL); ++ if (reg & ESPI_FLASH_TX_CTRL_TRIG_PEND) { ++ rc = -EBUSY; ++ goto unlock_mtx_n_out; ++ } ++ ++ pkt = vmalloc(ioc->pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; ++ } ++ ++ hdr = (struct espi_comm_hdr *)pkt; ++ ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } ++ ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ if (flash->dma.enable) { ++ memcpy(flash->dma.tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ dma_wmb(); ++ } else { ++ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) ++ writel(pkt[i], espi->regs + ESPI_FLASH_TX_DATA); + } + + cyc = hdr->cyc; + tag = hdr->tag; + len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ reg = FIELD_PREP(ESPI_OOB_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_OOB_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_OOB_TX_CTRL_LEN, len) -+ | ESPI_OOB_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_OOB_TX_CTRL); ++ reg = FIELD_PREP(ESPI_FLASH_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_FLASH_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_FLASH_TX_CTRL_LEN, len) ++ | ESPI_FLASH_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_FLASH_TX_CTRL); + + rc = 0; + @@ -67676,17 +68272,17 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&oob->tx_mtx); ++ mutex_unlock(&flash->tx_mtx); + + return rc; +} + -+static long ast2500_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static long ast2500_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2500_espi_oob *oob; ++ struct aspeed_espi_flash *flash; + struct aspeed_espi_ioc ioc; + -+ oob = container_of(fp->private_data, struct ast2500_espi_oob, mdev); ++ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -67695,10 +68291,10 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + return -EINVAL; + + switch (cmd) { -+ case ASPEED_ESPI_OOB_GET_RX: -+ return ast2500_espi_oob_get_rx(fp, oob, &ioc); -+ case ASPEED_ESPI_OOB_PUT_TX: -+ return ast2500_espi_oob_put_tx(fp, oob, &ioc); ++ case ASPEED_ESPI_FLASH_GET_RX: ++ return ast2500_espi_flash_get_rx(fp, flash, &ioc); ++ case ASPEED_ESPI_FLASH_PUT_TX: ++ return ast2500_espi_flash_put_tx(fp, flash, &ioc); + default: + break; + }; @@ -67706,184 +68302,645 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + return -EINVAL; +} + -+static const struct file_operations ast2500_espi_oob_fops = { ++static const struct file_operations ast2500_espi_flash_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2500_espi_oob_ioctl, ++ .unlocked_ioctl = ast2500_espi_flash_ioctl, +}; + -+static void ast2500_espi_oob_isr(struct ast2500_espi *espi) ++static void ast2500_espi_flash_isr(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_oob *oob; ++ struct aspeed_espi_flash *flash; + unsigned long flags; -+ uint32_t sts; ++ u32 sts; + -+ oob = &espi->oob; ++ flash = &espi->flash; + + sts = readl(espi->regs + ESPI_INT_STS); + -+ if (sts & ESPI_INT_STS_OOB_RX_CMPLT) { -+ writel(ESPI_INT_STS_OOB_RX_CMPLT, espi->regs + ESPI_INT_STS); ++ if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) { ++ spin_lock_irqsave(&flash->lock, flags); ++ flash->rx_ready = true; ++ spin_unlock_irqrestore(&flash->lock, flags); + -+ spin_lock_irqsave(&oob->lock, flags); -+ oob->rx_ready = true; -+ spin_unlock_irqrestore(&oob->lock, flags); ++ wake_up_interruptible(&flash->wq); + -+ wake_up_interruptible(&oob->wq); ++ writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); + } +} + -+static void ast2500_espi_oob_reset(struct ast2500_espi *espi) ++static void ast2500_espi_flash_reset(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_oob *oob; -+ uint32_t reg; -+ -+ oob = &espi->oob; ++ struct aspeed_espi_flash *flash = &espi->flash; ++ u32 reg; + + reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~(ESPI_INT_EN_OOB); ++ reg &= ~(ESPI_INT_EN_FLASH); + writel(reg, espi->regs + ESPI_INT_EN); -+ writel(ESPI_INT_STS_OOB, espi->regs + ESPI_INT_STS); ++ writel(ESPI_INT_STS_FLASH, espi->regs + ESPI_INT_STS); + + reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_OOB_TX_SW_RST -+ | ESPI_CTRL_OOB_RX_SW_RST -+ | ESPI_CTRL_OOB_TX_DMA_EN -+ | ESPI_CTRL_OOB_RX_DMA_EN -+ | ESPI_CTRL_OOB_SW_RDY); ++ reg &= ~(ESPI_CTRL_FLASH_TX_SW_RST ++ | ESPI_CTRL_FLASH_RX_SW_RST ++ | ESPI_CTRL_FLASH_TX_DMA_EN ++ | ESPI_CTRL_FLASH_RX_DMA_EN ++ | ESPI_CTRL_FLASH_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + + udelay(1); + -+ reg |= (ESPI_CTRL_OOB_TX_SW_RST | ESPI_CTRL_OOB_RX_SW_RST); ++ reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); + writel(reg, espi->regs + ESPI_CTRL); + -+ if (oob->dma.enable) { -+ writel(oob->dma.tx_addr, espi->regs + ESPI_OOB_TX_DMA); -+ writel(oob->dma.rx_addr, espi->regs + ESPI_OOB_RX_DMA); ++ if (flash->edaf.mode == EDAF_MODE_MIX) { ++ reg = FIELD_PREP(ESPI_FLASH_SAFS_TADDR_BASE, flash->edaf.taddr >> 24) ++ | FIELD_PREP(ESPI_FLASH_SAFS_TADDR_MASK, (~(flash->edaf.size - 1)) >> 24); ++ writel(reg, espi->regs + ESPI_FLASH_SAFS_TADDR); ++ } else { ++ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SAFS_SW_MODE; ++ writel(reg, espi->regs + ESPI_CTRL); ++ } ++ ++ if (flash->dma.enable) { ++ writel(flash->dma.tx_addr, espi->regs + ESPI_FLASH_TX_DMA); ++ writel(flash->dma.rx_addr, espi->regs + ESPI_FLASH_RX_DMA); + + reg = readl(espi->regs + ESPI_CTRL) -+ | ESPI_CTRL_OOB_TX_DMA_EN -+ | ESPI_CTRL_OOB_RX_DMA_EN; ++ | ESPI_CTRL_FLASH_TX_DMA_EN ++ | ESPI_CTRL_FLASH_RX_DMA_EN; + writel(reg, espi->regs + ESPI_CTRL); + } + -+ reg = readl(espi->regs + ESPI_INT_EN) | ESPI_INT_EN_OOB_RX_CMPLT; ++ reg = readl(espi->regs + ESPI_INT_EN) | ESPI_INT_EN_FLASH_RX_CMPLT; + writel(reg, espi->regs + ESPI_INT_EN); + -+ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_OOB_SW_RDY; ++ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SW_RDY; + writel(reg, espi->regs + ESPI_CTRL); +} + -+static int ast2500_espi_oob_probe(struct ast2500_espi *espi) ++int ast2500_espi_flash_probe(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_oob *oob; ++ struct aspeed_espi_flash *flash; + struct device *dev; + int rc; + + dev = espi->dev; + -+ oob = &espi->oob; ++ flash = &espi->flash; + -+ init_waitqueue_head(&oob->wq); ++ init_waitqueue_head(&flash->wq); + -+ spin_lock_init(&oob->lock); ++ spin_lock_init(&flash->lock); + -+ mutex_init(&oob->tx_mtx); -+ mutex_init(&oob->rx_mtx); ++ mutex_init(&flash->tx_mtx); ++ mutex_init(&flash->rx_mtx); + -+ oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); -+ if (oob->dma.enable) { -+ oob->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &oob->dma.tx_addr, GFP_KERNEL); -+ if (!oob->dma.tx_virt) { ++ flash->edaf.mode = EDAF_MODE_MIX; ++ ++ of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->edaf.mode); ++ if (flash->edaf.mode == EDAF_MODE_MIX) { ++ rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", (u32 *)&flash->edaf.taddr); ++ if (rc || !IS_ALIGNED(flash->edaf.taddr, FLASH_SAFS_ALIGN)) { ++ dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); ++ return -ENODEV; ++ } ++ ++ rc = of_property_read_u32(dev->of_node, "flash-safs-size", (u32 *)&flash->edaf.size); ++ if (rc || !IS_ALIGNED(flash->edaf.size, FLASH_SAFS_ALIGN)) { ++ dev_err(dev, "cannot get 16MB-aligned SAFS size\n"); ++ return -ENODEV; ++ } ++ } ++ ++ flash->dma.enable = of_property_read_bool(dev->of_node, "flash-dma-mode"); ++ if (flash->dma.enable) { ++ flash->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.tx_addr, GFP_KERNEL); ++ if (!flash->dma.tx_virt) { + dev_err(dev, "cannot allocate DMA TX buffer\n"); + return -ENOMEM; + } + -+ oob->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &oob->dma.rx_addr, GFP_KERNEL); -+ if (!oob->dma.rx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ flash->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.rx_addr, GFP_KERNEL); ++ if (!flash->dma.rx_virt) { ++ dev_err(dev, "cannot allocate DMA RX buffer\n"); + return -ENOMEM; + } + } + -+ oob->mdev.parent = dev; -+ oob->mdev.minor = MISC_DYNAMIC_MINOR; -+ oob->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-oob", DEVICE_NAME); -+ oob->mdev.fops = &ast2500_espi_oob_fops; -+ rc = misc_register(&oob->mdev); ++ flash->mdev.parent = dev; ++ flash->mdev.minor = MISC_DYNAMIC_MINOR; ++ flash->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-flash", DEVICE_NAME); ++ flash->mdev.fops = &ast2500_espi_flash_fops; ++ rc = misc_register(&flash->mdev); + if (rc) { -+ dev_err(dev, "cannot register device %s\n", oob->mdev.name); ++ dev_err(dev, "cannot register device %s\n", flash->mdev.name); + return rc; + } + -+ ast2500_espi_oob_reset(espi); ++ ast2500_espi_flash_reset(espi); ++ ++ return 0; ++} ++ ++int ast2500_espi_flash_remove(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_flash *flash; ++ struct device *dev; ++ u32 reg; ++ ++ dev = espi->dev; ++ ++ flash = &espi->flash; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~(ESPI_INT_EN_FLASH); ++ writel(reg, espi->regs + ESPI_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_FLASH_TX_DMA_EN ++ | ESPI_CTRL_FLASH_RX_DMA_EN ++ | ESPI_CTRL_FLASH_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ if (flash->dma.enable) { ++ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.rx_addr); ++ } ++ ++ mutex_destroy(&flash->tx_mtx); ++ mutex_destroy(&flash->rx_mtx); ++ ++ misc_deregister(&flash->mdev); ++ ++ return 0; ++} ++ ++/* global control */ ++irqreturn_t ast2500_espi_isr(int irq, void *arg) ++{ ++ struct aspeed_espi *espi; ++ u32 sts; ++ ++ espi = (struct aspeed_espi *)arg; ++ ++ sts = readl(espi->regs + ESPI_INT_STS); ++ if (!sts) ++ return IRQ_NONE; ++ ++ if (sts & ESPI_INT_STS_PERIF) ++ ast2500_espi_perif_isr(espi); ++ ++ if (sts & ESPI_INT_STS_VW) ++ ast2500_espi_vw_isr(espi); ++ ++ if (sts & ESPI_INT_STS_OOB) ++ ast2500_espi_oob_isr(espi); ++ ++ if (sts & ESPI_INT_STS_FLASH) ++ ast2500_espi_flash_isr(espi); ++ ++ if (sts & ESPI_INT_STS_RST_DEASSERT) { ++ ast2500_espi_perif_reset(espi); ++ ast2500_espi_vw_reset(espi); ++ ast2500_espi_oob_reset(espi); ++ ast2500_espi_flash_reset(espi); ++ writel(ESPI_INT_STS_RST_DEASSERT, espi->regs + ESPI_INT_STS); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++void ast2500_espi_pre_init(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~ESPI_INT_EN_RST_DEASSERT; ++ writel(reg, espi->regs + ESPI_INT_EN); ++} ++ ++void ast2500_espi_post_init(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg |= ESPI_INT_EN_RST_DEASSERT; ++ writel(reg, espi->regs + ESPI_INT_EN); ++} ++ ++void ast2500_espi_deinit(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~(ESPI_INT_EN_RST_DEASSERT); ++ writel(reg, espi->regs + ESPI_INT_EN); ++} +diff --git a/drivers/soc/aspeed/espi/ast2500-espi.h b/drivers/soc/aspeed/espi/ast2500-espi.h +--- a/drivers/soc/aspeed/espi/ast2500-espi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2500-espi.h 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,258 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Register definitions for Aspeed AST2500 eSPI controller ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#ifndef _AST2500_ESPI_H_ ++#define _AST2500_ESPI_H_ ++ ++#include ++#include ++#include "aspeed-espi.h" ++ ++/* registers */ ++#define ESPI_CTRL 0x000 ++#define ESPI_CTRL_FLASH_TX_SW_RST BIT(31) ++#define ESPI_CTRL_FLASH_RX_SW_RST BIT(30) ++#define ESPI_CTRL_OOB_TX_SW_RST BIT(29) ++#define ESPI_CTRL_OOB_RX_SW_RST BIT(28) ++#define ESPI_CTRL_PERIF_NP_TX_SW_RST BIT(27) ++#define ESPI_CTRL_PERIF_NP_RX_SW_RST BIT(26) ++#define ESPI_CTRL_PERIF_PC_TX_SW_RST BIT(25) ++#define ESPI_CTRL_PERIF_PC_RX_SW_RST BIT(24) ++#define ESPI_CTRL_FLASH_TX_DMA_EN BIT(23) ++#define ESPI_CTRL_FLASH_RX_DMA_EN BIT(22) ++#define ESPI_CTRL_OOB_TX_DMA_EN BIT(21) ++#define ESPI_CTRL_OOB_RX_DMA_EN BIT(20) ++#define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) ++#define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) ++#define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) ++#define ESPI_CTRL_FLASH_SAFS_SW_MODE BIT(10) ++#define ESPI_CTRL_VW_GPIO_SW BIT(9) ++#define ESPI_CTRL_FLASH_SW_RDY BIT(7) ++#define ESPI_CTRL_OOB_SW_RDY BIT(4) ++#define ESPI_CTRL_VW_SW_RDY BIT(3) ++#define ESPI_CTRL_PERIF_SW_RDY BIT(1) ++#define ESPI_STS 0x004 ++#define ESPI_INT_STS 0x008 ++#define ESPI_INT_STS_RST_DEASSERT BIT(31) ++#define ESPI_INT_STS_OOB_RX_TMOUT BIT(23) ++#define ESPI_INT_STS_VW_SYSEVT1 BIT(22) ++#define ESPI_INT_STS_FLASH_TX_ERR BIT(21) ++#define ESPI_INT_STS_OOB_TX_ERR BIT(20) ++#define ESPI_INT_STS_FLASH_TX_ABT BIT(19) ++#define ESPI_INT_STS_OOB_TX_ABT BIT(18) ++#define ESPI_INT_STS_PERIF_NP_TX_ABT BIT(17) ++#define ESPI_INT_STS_PERIF_PC_TX_ABT BIT(16) ++#define ESPI_INT_STS_FLASH_RX_ABT BIT(15) ++#define ESPI_INT_STS_OOB_RX_ABT BIT(14) ++#define ESPI_INT_STS_PERIF_NP_RX_ABT BIT(13) ++#define ESPI_INT_STS_PERIF_PC_RX_ABT BIT(12) ++#define ESPI_INT_STS_PERIF_NP_TX_ERR BIT(11) ++#define ESPI_INT_STS_PERIF_PC_TX_ERR BIT(10) ++#define ESPI_INT_STS_VW_GPIO BIT(9) ++#define ESPI_INT_STS_VW_SYSEVT BIT(8) ++#define ESPI_INT_STS_FLASH_TX_CMPLT BIT(7) ++#define ESPI_INT_STS_FLASH_RX_CMPLT BIT(6) ++#define ESPI_INT_STS_OOB_TX_CMPLT BIT(5) ++#define ESPI_INT_STS_OOB_RX_CMPLT BIT(4) ++#define ESPI_INT_STS_PERIF_NP_TX_CMPLT BIT(3) ++#define ESPI_INT_STS_PERIF_PC_TX_CMPLT BIT(1) ++#define ESPI_INT_STS_PERIF_PC_RX_CMPLT BIT(0) ++#define ESPI_INT_EN 0x00c ++#define ESPI_INT_EN_RST_DEASSERT BIT(31) ++#define ESPI_INT_EN_OOB_RX_TMOUT BIT(23) ++#define ESPI_INT_EN_VW_SYSEVT1 BIT(22) ++#define ESPI_INT_EN_FLASH_TX_ERR BIT(21) ++#define ESPI_INT_EN_OOB_TX_ERR BIT(20) ++#define ESPI_INT_EN_FLASH_TX_ABT BIT(19) ++#define ESPI_INT_EN_OOB_TX_ABT BIT(18) ++#define ESPI_INT_EN_PERIF_NP_TX_ABT BIT(17) ++#define ESPI_INT_EN_PERIF_PC_TX_ABT BIT(16) ++#define ESPI_INT_EN_FLASH_RX_ABT BIT(15) ++#define ESPI_INT_EN_OOB_RX_ABT BIT(14) ++#define ESPI_INT_EN_PERIF_NP_RX_ABT BIT(13) ++#define ESPI_INT_EN_PERIF_PC_RX_ABT BIT(12) ++#define ESPI_INT_EN_PERIF_NP_TX_ERR BIT(11) ++#define ESPI_INT_EN_PERIF_PC_TX_ERR BIT(10) ++#define ESPI_INT_EN_VW_GPIO BIT(9) ++#define ESPI_INT_EN_VW_SYSEVT BIT(8) ++#define ESPI_INT_EN_FLASH_TX_CMPLT BIT(7) ++#define ESPI_INT_EN_FLASH_RX_CMPLT BIT(6) ++#define ESPI_INT_EN_OOB_TX_CMPLT BIT(5) ++#define ESPI_INT_EN_OOB_RX_CMPLT BIT(4) ++#define ESPI_INT_EN_PERIF_NP_TX_CMPLT BIT(3) ++#define ESPI_INT_EN_PERIF_PC_TX_CMPLT BIT(1) ++#define ESPI_INT_EN_PERIF_PC_RX_CMPLT BIT(0) ++#define ESPI_PERIF_PC_RX_DMA 0x010 ++#define ESPI_PERIF_PC_RX_CTRL 0x014 ++#define ESPI_PERIF_PC_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_PERIF_PC_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_PERIF_PC_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_PERIF_PC_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_PERIF_PC_RX_DATA 0x018 ++#define ESPI_PERIF_PC_TX_DMA 0x020 ++#define ESPI_PERIF_PC_TX_CTRL 0x024 ++#define ESPI_PERIF_PC_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_PERIF_PC_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_PERIF_PC_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_PERIF_PC_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_PERIF_PC_TX_DATA 0x028 ++#define ESPI_PERIF_NP_TX_DMA 0x030 ++#define ESPI_PERIF_NP_TX_CTRL 0x034 ++#define ESPI_PERIF_NP_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_PERIF_NP_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_PERIF_NP_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_PERIF_NP_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_PERIF_NP_TX_DATA 0x038 ++#define ESPI_OOB_RX_DMA 0x040 ++#define ESPI_OOB_RX_CTRL 0x044 ++#define ESPI_OOB_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_OOB_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_OOB_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_OOB_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_OOB_RX_DATA 0x048 ++#define ESPI_OOB_TX_DMA 0x050 ++#define ESPI_OOB_TX_CTRL 0x054 ++#define ESPI_OOB_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_OOB_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_OOB_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_OOB_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_OOB_TX_DATA 0x058 ++#define ESPI_FLASH_RX_DMA 0x060 ++#define ESPI_FLASH_RX_CTRL 0x064 ++#define ESPI_FLASH_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_FLASH_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_FLASH_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_FLASH_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_FLASH_RX_DATA 0x068 ++#define ESPI_FLASH_TX_DMA 0x070 ++#define ESPI_FLASH_TX_CTRL 0x074 ++#define ESPI_FLASH_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_FLASH_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_FLASH_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_FLASH_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_FLASH_TX_DATA 0x078 ++#define ESPI_PERIF_MCYC_SADDR 0x084 ++#define ESPI_PERIF_MCYC_TADDR 0x088 ++#define ESPI_PERIF_MCYC_MASK 0x08c ++#define ESPI_FLASH_SAFS_TADDR 0x090 ++#define ESPI_FLASH_SAFS_TADDR_BASE GENMASK(31, 24) ++#define ESPI_FLASH_SAFS_TADDR_MASK GENMASK(15, 8) ++#define ESPI_VW_SYSEVT_INT_EN 0x094 ++#define ESPI_VW_SYSEVT_INT_EN_HOST_RST_WARN BIT(8) ++#define ESPI_VW_SYSEVT_INT_EN_OOB_RST_WARN BIT(6) ++#define ESPI_VW_SYSEVT 0x098 ++#define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) ++#define ESPI_VW_SYSEVT_SLV_BOOT_STS BIT(23) ++#define ESPI_VW_SYSEVT_SLV_BOOT_DONE BIT(20) ++#define ESPI_VW_SYSEVT_OOB_RST_ACK BIT(16) ++#define ESPI_VW_SYSEVT_HOST_RST_WARN BIT(8) ++#define ESPI_VW_SYSEVT_OOB_RST_WARN BIT(6) ++#define ESPI_VW_GPIO_VAL 0x09c ++#define ESPI_GEN_CAP_N_CONF 0x0a0 ++#define ESPI_CH0_CAP_N_CONF 0x0a4 ++#define ESPI_CH1_CAP_N_CONF 0x0a8 ++#define ESPI_CH2_CAP_N_CONF 0x0ac ++#define ESPI_CH3_CAP_N_CONF 0x0b0 ++#define ESPI_CH3_CAP_N_CONF2 0x0b4 ++#define ESPI_VW_GPIO_DIR 0x0c0 ++#define ESPI_VW_GPIO_GRP 0x0c4 ++#define ESPI_VW_SYSEVT1_INT_EN 0x100 ++#define ESPI_VW_SYSEVT1_INT_EN_SUSPEND_WARN BIT(0) ++#define ESPI_VW_SYSEVT1 0x104 ++#define ESPI_VW_SYSEVT1_SUSPEND_ACK BIT(20) ++#define ESPI_VW_SYSEVT1_SUSPEND_WARN BIT(0) ++#define ESPI_VW_SYSEVT_INT_T0 0x110 ++#define ESPI_VW_SYSEVT_INT_T1 0x114 ++#define ESPI_VW_SYSEVT_INT_T2 0x118 ++#define ESPI_VW_SYSEVT_INT_T2_HOST_RST_WARN BIT(8) ++#define ESPI_VW_SYSEVT_INT_T2_OOB_RST_WARN BIT(6) ++#define ESPI_VW_SYSEVT_INT_STS 0x11c ++#define ESPI_VW_SYSEVT_INT_STS_HOST_RST_WARN BIT(8) ++#define ESPI_VW_SYSEVT_INT_STS_OOB_RST_WARN BIT(6) ++#define ESPI_VW_SYSEVT1_INT_T0 0x120 ++#define ESPI_VW_SYSEVT1_INT_T0_SUSPEND_WARN BIT(0) ++#define ESPI_VW_SYSEVT1_INT_T1 0x124 ++#define ESPI_VW_SYSEVT1_INT_T2 0x128 ++#define ESPI_VW_SYSEVT1_INT_STS 0x12c ++#define ESPI_VW_SYSEVT1_INT_STS_SUSPEND_WARN BIT(0) ++ ++/* collect ESPI_INT_EN bits for convenience */ ++#define ESPI_INT_EN_PERIF \ ++ (ESPI_INT_EN_PERIF_NP_TX_ABT | \ ++ ESPI_INT_EN_PERIF_PC_TX_ABT | \ ++ ESPI_INT_EN_PERIF_NP_RX_ABT | \ ++ ESPI_INT_EN_PERIF_PC_RX_ABT | \ ++ ESPI_INT_EN_PERIF_NP_TX_ERR | \ ++ ESPI_INT_EN_PERIF_PC_TX_ERR | \ ++ ESPI_INT_EN_PERIF_NP_TX_CMPLT | \ ++ ESPI_INT_EN_PERIF_PC_TX_CMPLT | \ ++ ESPI_INT_EN_PERIF_PC_RX_CMPLT) ++ ++#define ESPI_INT_EN_VW \ ++ (ESPI_INT_EN_VW_SYSEVT1 | \ ++ ESPI_INT_EN_VW_GPIO | \ ++ ESPI_INT_EN_VW_SYSEVT) ++ ++#define ESPI_INT_EN_OOB \ ++ (ESPI_INT_EN_OOB_RX_TMOUT | \ ++ ESPI_INT_EN_OOB_TX_ERR | \ ++ ESPI_INT_EN_OOB_TX_ABT | \ ++ ESPI_INT_EN_OOB_RX_ABT | \ ++ ESPI_INT_EN_OOB_TX_CMPLT | \ ++ ESPI_INT_EN_OOB_RX_CMPLT) ++ ++#define ESPI_INT_EN_FLASH \ ++ (ESPI_INT_EN_FLASH_TX_ERR | \ ++ ESPI_INT_EN_FLASH_TX_ABT | \ ++ ESPI_INT_EN_FLASH_RX_ABT | \ ++ ESPI_INT_EN_FLASH_TX_CMPLT | \ ++ ESPI_INT_EN_FLASH_RX_CMPLT) ++ ++/* collect ESPI_INT_STS bits for convenience */ ++#define ESPI_INT_STS_PERIF \ ++ (ESPI_INT_STS_PERIF_NP_TX_ABT | \ ++ ESPI_INT_STS_PERIF_PC_TX_ABT | \ ++ ESPI_INT_STS_PERIF_NP_RX_ABT | \ ++ ESPI_INT_STS_PERIF_PC_RX_ABT | \ ++ ESPI_INT_STS_PERIF_NP_TX_ERR | \ ++ ESPI_INT_STS_PERIF_PC_TX_ERR | \ ++ ESPI_INT_STS_PERIF_NP_TX_CMPLT | \ ++ ESPI_INT_STS_PERIF_PC_TX_CMPLT | \ ++ ESPI_INT_STS_PERIF_PC_RX_CMPLT) ++ ++#define ESPI_INT_STS_VW \ ++ (ESPI_INT_STS_VW_SYSEVT1 | \ ++ ESPI_INT_STS_VW_GPIO | \ ++ ESPI_INT_STS_VW_SYSEVT) ++ ++#define ESPI_INT_STS_OOB \ ++ (ESPI_INT_STS_OOB_RX_TMOUT | \ ++ ESPI_INT_STS_OOB_TX_ERR | \ ++ ESPI_INT_STS_OOB_TX_ABT | \ ++ ESPI_INT_STS_OOB_RX_ABT | \ ++ ESPI_INT_STS_OOB_TX_CMPLT | \ ++ ESPI_INT_STS_OOB_RX_CMPLT) ++ ++#define ESPI_INT_STS_FLASH \ ++ (ESPI_INT_STS_FLASH_TX_ERR | \ ++ ESPI_INT_STS_FLASH_TX_ABT | \ ++ ESPI_INT_STS_FLASH_RX_ABT | \ ++ ESPI_INT_STS_FLASH_TX_CMPLT | \ ++ ESPI_INT_STS_FLASH_RX_CMPLT) ++ ++/* operators for framework initialization */ ++void ast2500_espi_pre_init(struct aspeed_espi *espi); ++void ast2500_espi_post_init(struct aspeed_espi *espi); ++void ast2500_espi_deinit(struct aspeed_espi *espi); ++int ast2500_espi_perif_probe(struct aspeed_espi *espi); ++int ast2500_espi_perif_remove(struct aspeed_espi *espi); ++int ast2500_espi_vw_probe(struct aspeed_espi *espi); ++int ast2500_espi_vw_remove(struct aspeed_espi *espi); ++int ast2500_espi_oob_probe(struct aspeed_espi *espi); ++int ast2500_espi_oob_remove(struct aspeed_espi *espi); ++int ast2500_espi_flash_probe(struct aspeed_espi *espi); ++int ast2500_espi_flash_remove(struct aspeed_espi *espi); ++irqreturn_t ast2500_espi_isr(int irq, void *arg); ++#endif +diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/ast2600-espi.c +--- a/drivers/soc/aspeed/espi/ast2600-espi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2600-espi.c 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,1910 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ast2600-espi.h" ++#include "aspeed-espi-comm.h" ++#include "aspeed-espi.h" ++ ++#define PERIF_MCYC_ALIGN SZ_64K ++#define PERIF_MMBI_ALIGN SZ_64K ++#define PERIF_MMBI_INST_NUM 8 ++ ++#define OOB_DMA_RPTR_KEY 0x45538073 ++#define OOB_DMA_DESC_NUM 8 ++#define OOB_DMA_DESC_CUSTOM 0x4 ++ ++#define FLASH_EDAF_ALIGN SZ_16M ++ ++/* peripheral channel (CH0) */ ++static int ast2600_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vma) ++{ ++ struct aspeed_espi_perif_mmbi *mmbi; ++ struct aspeed_espi_perif *perif; ++ struct aspeed_espi *espi; ++ unsigned long vm_size; ++ pgprot_t prot; ++ ++ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, b2h_mdev); ++ ++ perif = mmbi->perif; ++ ++ espi = container_of(perif, struct aspeed_espi, perif); ++ ++ vm_size = vma->vm_end - vma->vm_start; ++ prot = vma->vm_page_prot; ++ ++ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > (SZ_4K << perif->mmbi.inst_size)) ++ return -EINVAL; ++ ++ prot = pgprot_noncached(prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, ++ (mmbi->b2h_addr >> PAGE_SHIFT) + vma->vm_pgoff, ++ vm_size, prot)) ++ return -EAGAIN; + + return 0; +} + -+static int ast2500_espi_oob_remove(struct ast2500_espi *espi) ++static int ast2600_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct ast2500_espi_oob *oob; -+ struct device *dev; -+ uint32_t reg; ++ struct aspeed_espi_perif_mmbi *mmbi; ++ struct aspeed_espi_perif *perif; ++ struct aspeed_espi *espi; ++ unsigned long vm_size; ++ pgprot_t prot; + -+ dev = espi->dev; ++ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); + -+ oob = &espi->oob; ++ perif = mmbi->perif; + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~(ESPI_INT_EN_OOB); -+ writel(reg, espi->regs + ESPI_INT_EN); ++ espi = container_of(perif, struct aspeed_espi, perif); + -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_OOB_TX_DMA_EN -+ | ESPI_CTRL_OOB_RX_DMA_EN -+ | ESPI_CTRL_OOB_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); ++ vm_size = vma->vm_end - vma->vm_start; ++ prot = vma->vm_page_prot; + -+ if (oob->dma.enable) { -+ dmam_free_coherent(dev, PAGE_SIZE, oob->dma.tx_virt, oob->dma.tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, oob->dma.rx_virt, oob->dma.rx_addr); -+ } ++ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > (SZ_4K << perif->mmbi.inst_size)) ++ return -EINVAL; + -+ mutex_destroy(&oob->tx_mtx); -+ mutex_destroy(&oob->rx_mtx); ++ prot = pgprot_noncached(prot); + -+ misc_deregister(&oob->mdev); ++ if (remap_pfn_range(vma, vma->vm_start, ++ (mmbi->h2b_addr >> PAGE_SHIFT) + vma->vm_pgoff, ++ vm_size, prot)) ++ return -EAGAIN; + + return 0; +} + -+/* flash channel (CH3) */ -+static long ast2500_espi_flash_get_rx(struct file *fp, -+ struct ast2500_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) ++static __poll_t ast2600_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) ++{ ++ struct aspeed_espi_perif_mmbi *mmbi; ++ ++ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); ++ ++ poll_wait(fp, &mmbi->wq, pt); ++ ++ if (!mmbi->host_rwp_update) ++ return 0; ++ ++ mmbi->host_rwp_update = false; ++ ++ return EPOLLIN; ++} ++ ++static long ast2600_espi_perif_pc_get_rx(struct file *fp, ++ struct aspeed_espi_perif *perif, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; ++ u32 pkt_len; ++ u8 *pkt; + int i, rc; + -+ rc = 0; -+ -+ espi = container_of(flash, struct ast2500_espi, flash); ++ espi = container_of(perif, struct aspeed_espi, perif); + + if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&flash->rx_mtx)) ++ if (!mutex_trylock(&perif->pc_rx_mtx)) + return -EAGAIN; + -+ if (!flash->rx_ready) { ++ if (!perif->rx_ready) { + rc = -ENODATA; + goto unlock_mtx_n_out; + } + } else { -+ mutex_lock(&flash->rx_mtx); ++ mutex_lock(&perif->pc_rx_mtx); + -+ if (!flash->rx_ready) { -+ rc = wait_event_interruptible(flash->wq, flash->rx_ready); ++ if (!perif->rx_ready) { ++ rc = wait_event_interruptible(perif->wq, perif->rx_ready); + if (rc == -ERESTARTSYS) { + rc = -EINTR; + goto unlock_mtx_n_out; @@ -67895,10 +68952,10 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + * common header (i.e. cycle type, tag, and length) + * part is written to HW registers + */ -+ reg = readl(espi->regs + ESPI_FLASH_RX_CTRL); -+ cyc = FIELD_GET(ESPI_FLASH_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_FLASH_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_FLASH_RX_CTRL_LEN, reg); ++ reg = readl(espi->regs + ESPI_PERIF_PC_RX_CTRL); ++ cyc = FIELD_GET(ESPI_PERIF_PC_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_PERIF_PC_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_PERIF_PC_RX_CTRL_LEN, reg); + + /* + * calculate the length of the rest part of the @@ -67906,24 +68963,23 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + * user space. + */ + switch (cyc) { -+ case ESPI_FLASH_WRITE: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_flash_rwe); ++ case ESPI_PERIF_MSG: ++ pkt_len = sizeof(struct espi_perif_msg); + break; -+ case ESPI_FLASH_READ: -+ case ESPI_FLASH_ERASE: -+ pkt_len = sizeof(struct espi_flash_rwe); ++ case ESPI_PERIF_MSG_D: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_perif_msg); + break; -+ case ESPI_FLASH_SUC_CMPLT_D_MIDDLE: -+ case ESPI_FLASH_SUC_CMPLT_D_FIRST: -+ case ESPI_FLASH_SUC_CMPLT_D_LAST: -+ case ESPI_FLASH_SUC_CMPLT_D_ONLY: ++ case ESPI_PERIF_SUC_CMPLT_D_MIDDLE: ++ case ESPI_PERIF_SUC_CMPLT_D_FIRST: ++ case ESPI_PERIF_SUC_CMPLT_D_LAST: ++ case ESPI_PERIF_SUC_CMPLT_D_ONLY: + pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_flash_cmplt); ++ sizeof(struct espi_perif_cmplt); + break; -+ case ESPI_FLASH_SUC_CMPLT: -+ case ESPI_FLASH_UNSUC_CMPLT: -+ pkt_len = sizeof(struct espi_flash_cmplt); ++ case ESPI_PERIF_SUC_CMPLT: ++ case ESPI_PERIF_UNSUC_CMPLT: ++ pkt_len = sizeof(struct espi_perif_cmplt); + break; + default: + rc = -EFAULT; @@ -67947,11 +69003,11 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + hdr->len_h = len >> 8; + hdr->len_l = len & 0xff; + -+ if (flash->dma.enable) { -+ memcpy(hdr + 1, flash->dma.rx_virt, pkt_len - sizeof(*hdr)); ++ if (perif->dma.enable) { ++ memcpy(hdr + 1, perif->dma.pc_rx_virt, pkt_len - sizeof(*hdr)); + } else { + for (i = sizeof(*hdr); i < pkt_len; ++i) -+ pkt[i] = readl(espi->regs + ESPI_FLASH_RX_DATA) & 0xff; ++ reg = readl(espi->regs + ESPI_PERIF_PC_RX_DATA) & 0xff; + } + + if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { @@ -67959,12 +69015,12 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + goto free_n_out; + } + -+ spin_lock_irqsave(&flash->lock, flags); ++ spin_lock_irqsave(&perif->lock, flags); + -+ writel(ESPI_FLASH_RX_CTRL_SERV_PEND, espi->regs + ESPI_FLASH_RX_CTRL); -+ flash->rx_ready = 0; ++ writel(ESPI_PERIF_PC_RX_CTRL_SERV_PEND, espi->regs + ESPI_PERIF_PC_RX_CTRL); ++ perif->rx_ready = 0; + -+ spin_unlock_irqrestore(&flash->lock, flags); ++ spin_unlock_irqrestore(&perif->lock, flags); + + rc = 0; + @@ -67972,36 +69028,36 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&flash->rx_mtx); ++ mutex_unlock(&perif->pc_rx_mtx); + + return rc; +} + -+static long ast2500_espi_flash_put_tx(struct file *fp, -+ struct ast2500_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) ++static long ast2600_espi_perif_pc_put_tx(struct file *fp, ++ struct aspeed_espi_perif *perif, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2500_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(flash, struct ast2500_espi, flash); ++ espi = container_of(perif, struct aspeed_espi, perif); + -+ if (!mutex_trylock(&flash->tx_mtx)) ++ if (!mutex_trylock(&perif->pc_tx_mtx)) + return -EAGAIN; + -+ reg = readl(espi->regs + ESPI_FLASH_TX_CTRL); -+ if (reg & ESPI_FLASH_TX_CTRL_TRIG_PEND) { ++ reg = readl(espi->regs + ESPI_PERIF_PC_TX_CTRL); ++ if (reg & ESPI_PERIF_PC_TX_CTRL_TRIG_PEND) { + rc = -EBUSY; -+ goto unlock_mtx_n_out; ++ goto unlock_n_out; + } + + pkt = vmalloc(ioc->pkt_len); + if (!pkt) { + rc = -ENOMEM; -+ goto unlock_mtx_n_out; ++ goto unlock_n_out; + } + + hdr = (struct espi_comm_hdr *)pkt; @@ -68015,41 +69071,108 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + * common header (i.e. cycle type, tag, and length) + * part is written to HW registers + */ -+ if (flash->dma.enable) { -+ memcpy(flash->dma.tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ if (perif->dma.enable) { ++ memcpy(perif->dma.pc_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); + dma_wmb(); + } else { + for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_FLASH_TX_DATA); ++ writel(pkt[i], espi->regs + ESPI_PERIF_PC_TX_DATA); + } + + cyc = hdr->cyc; + tag = hdr->tag; + len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ reg = FIELD_PREP(ESPI_FLASH_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_FLASH_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_FLASH_TX_CTRL_LEN, len) -+ | ESPI_FLASH_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_FLASH_TX_CTRL); ++ reg = FIELD_PREP(ESPI_PERIF_PC_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_PERIF_PC_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_PERIF_PC_TX_CTRL_LEN, len) ++ | ESPI_PERIF_PC_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_PERIF_PC_TX_CTRL); + + rc = 0; + +free_n_out: + vfree(pkt); + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->tx_mtx); ++unlock_n_out: ++ mutex_unlock(&perif->pc_tx_mtx); + + return rc; +} + -+static long ast2500_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static long ast2600_espi_perif_np_put_tx(struct file *fp, ++ struct aspeed_espi_perif *perif, ++ struct aspeed_espi_ioc *ioc) ++{ ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u8 *pkt; ++ int i, rc; ++ ++ espi = container_of(perif, struct aspeed_espi, perif); ++ ++ if (!mutex_trylock(&perif->np_tx_mtx)) ++ return -EAGAIN; ++ ++ reg = readl(espi->regs + ESPI_PERIF_NP_TX_CTRL); ++ if (reg & ESPI_PERIF_NP_TX_CTRL_TRIG_PEND) { ++ rc = -EBUSY; ++ goto unlock_n_out; ++ } ++ ++ pkt = vmalloc(ioc->pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_n_out; ++ } ++ ++ hdr = (struct espi_comm_hdr *)pkt; ++ ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } ++ ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ if (perif->dma.enable) { ++ memcpy(perif->dma.np_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ dma_wmb(); ++ } else { ++ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) ++ writel(pkt[i], espi->regs + ESPI_PERIF_NP_TX_DATA); ++ } ++ ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ ++ reg = FIELD_PREP(ESPI_PERIF_NP_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_PERIF_NP_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_PERIF_NP_TX_CTRL_LEN, len) ++ | ESPI_PERIF_NP_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_PERIF_NP_TX_CTRL); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++unlock_n_out: ++ mutex_unlock(&perif->np_tx_mtx); ++ ++ return rc; ++} ++ ++static long ast2600_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2500_espi_flash *flash; ++ struct aspeed_espi_perif *perif; + struct aspeed_espi_ioc ioc; + -+ flash = container_of(fp->private_data, struct ast2500_espi_flash, mdev); ++ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -68058,10 +69181,12 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + return -EINVAL; + + switch (cmd) { -+ case ASPEED_ESPI_FLASH_GET_RX: -+ return ast2500_espi_flash_get_rx(fp, flash, &ioc); -+ case ASPEED_ESPI_FLASH_PUT_TX: -+ return ast2500_espi_flash_put_tx(fp, flash, &ioc); ++ case ASPEED_ESPI_PERIF_PC_GET_RX: ++ return ast2600_espi_perif_pc_get_rx(fp, perif, &ioc); ++ case ASPEED_ESPI_PERIF_PC_PUT_TX: ++ return ast2600_espi_perif_pc_put_tx(fp, perif, &ioc); ++ case ASPEED_ESPI_PERIF_NP_PUT_TX: ++ return ast2600_espi_perif_np_put_tx(fp, perif, &ioc); + default: + break; + }; @@ -68069,920 +69194,1112 @@ diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/ast2500-espi + return -EINVAL; +} + -+static const struct file_operations ast2500_espi_flash_fops = { ++static int ast2600_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) ++{ ++ struct aspeed_espi_perif *perif; ++ unsigned long vm_size; ++ pgprot_t vm_prot; ++ ++ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ if (!perif->mcyc.enable) ++ return -EPERM; ++ ++ vm_size = vma->vm_end - vma->vm_start; ++ vm_prot = vma->vm_page_prot; ++ ++ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > perif->mcyc.size) ++ return -EINVAL; ++ ++ vm_prot = pgprot_noncached(vm_prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, ++ (perif->mcyc.taddr >> PAGE_SHIFT) + vma->vm_pgoff, ++ vm_size, vm_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static const struct file_operations ast2600_espi_mmbi_b2h_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2500_espi_flash_ioctl, ++ .mmap = ast2600_espi_mmbi_b2h_mmap, ++}; ++ ++static const struct file_operations ast2600_espi_mmbi_h2b_fops = { ++ .owner = THIS_MODULE, ++ .mmap = ast2600_espi_mmbi_h2b_mmap, ++ .poll = ast2600_espi_mmbi_h2b_poll, ++}; ++ ++static const struct file_operations ast2600_espi_perif_fops = { ++ .owner = THIS_MODULE, ++ .mmap = ast2600_espi_perif_mmap, ++ .unlocked_ioctl = ast2600_espi_perif_ioctl, +}; + -+static void ast2500_espi_flash_isr(struct ast2500_espi *espi) ++static irqreturn_t ast2600_espi_perif_mmbi_isr(int irq, void *arg) ++{ ++ struct aspeed_espi_perif_mmbi *mmbi; ++ struct aspeed_espi_perif *perif; ++ struct aspeed_espi *espi; ++ u32 sts, tmp; ++ u32 *p; ++ int i; ++ ++ espi = (struct aspeed_espi *)arg; ++ ++ perif = &espi->perif; ++ ++ sts = readl(espi->regs + ESPI_MMBI_INT_STS); ++ if (!sts) ++ return IRQ_NONE; ++ ++ for (i = 0, tmp = sts; i < PERIF_MMBI_INST_NUM; ++i, tmp >>= 2) { ++ if (!(tmp & 0x3)) ++ continue; ++ ++ mmbi = &perif->mmbi.inst[i]; ++ ++ p = (u32 *)mmbi->h2b_virt; ++ p[0] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i)); ++ p[1] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i) + 4); ++ ++ mmbi->host_rwp_update = true; ++ ++ wake_up_interruptible(&mmbi->wq); ++ } ++ ++ writel(sts, espi->regs + ESPI_MMBI_INT_STS); ++ ++ return IRQ_HANDLED; ++} ++ ++static void ast2600_espi_perif_isr(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_flash *flash; ++ struct aspeed_espi_perif *perif; + unsigned long flags; -+ uint32_t sts; ++ u32 sts; + -+ flash = &espi->flash; ++ perif = &espi->perif; + + sts = readl(espi->regs + ESPI_INT_STS); + -+ if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) { -+ spin_lock_irqsave(&flash->lock, flags); -+ flash->rx_ready = true; -+ spin_unlock_irqrestore(&flash->lock, flags); ++ if (sts & ESPI_INT_STS_PERIF_PC_RX_CMPLT) { ++ writel(ESPI_INT_STS_PERIF_PC_RX_CMPLT, espi->regs + ESPI_INT_STS); + -+ wake_up_interruptible(&flash->wq); ++ spin_lock_irqsave(&perif->lock, flags); ++ perif->rx_ready = true; ++ spin_unlock_irqrestore(&perif->lock, flags); + -+ writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); ++ wake_up_interruptible(&perif->wq); + } +} + -+static void ast2500_espi_flash_reset(struct ast2500_espi *espi) ++static void ast2600_espi_perif_sw_reset(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_flash *flash = &espi->flash; -+ uint32_t reg; ++ struct device *dev; ++ u32 reg; + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~(ESPI_INT_EN_FLASH); -+ writel(reg, espi->regs + ESPI_INT_EN); -+ writel(ESPI_INT_STS_FLASH, espi->regs + ESPI_INT_STS); ++ dev = espi->dev; + + reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_FLASH_TX_SW_RST -+ | ESPI_CTRL_FLASH_RX_SW_RST -+ | ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN -+ | ESPI_CTRL_FLASH_SW_RDY); ++ reg &= ~(ESPI_CTRL_PERIF_NP_TX_SW_RST ++ | ESPI_CTRL_PERIF_NP_RX_SW_RST ++ | ESPI_CTRL_PERIF_PC_TX_SW_RST ++ | ESPI_CTRL_PERIF_PC_RX_SW_RST ++ | ESPI_CTRL_PERIF_NP_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_RX_DMA_EN ++ | ESPI_CTRL_PERIF_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + + udelay(1); + -+ reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); ++ reg |= (ESPI_CTRL_PERIF_NP_TX_SW_RST ++ | ESPI_CTRL_PERIF_NP_RX_SW_RST ++ | ESPI_CTRL_PERIF_PC_TX_SW_RST ++ | ESPI_CTRL_PERIF_PC_RX_SW_RST); + writel(reg, espi->regs + ESPI_CTRL); ++} + -+ if (flash->safs.mode == SAFS_MODE_MIX) { -+ reg = FIELD_PREP(ESPI_FLASH_SAFS_TADDR_BASE, flash->safs.taddr >> 24) -+ | FIELD_PREP(ESPI_FLASH_SAFS_TADDR_MASK, (~(flash->safs.size - 1)) >> 24); -+ writel(reg, espi->regs + ESPI_FLASH_SAFS_TADDR); -+ } else { -+ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SAFS_SW_MODE; -+ writel(reg, espi->regs + ESPI_CTRL); ++static void ast2600_espi_perif_reset(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_perif *perif; ++ struct device *dev; ++ u32 reg, mask; ++ ++ dev = espi->dev; ++ ++ perif = &espi->perif; ++ ++ writel(ESPI_INT_EN_PERIF, espi->regs + ESPI_INT_EN_CLR); ++ writel(ESPI_INT_STS_PERIF, espi->regs + ESPI_INT_STS); ++ ++ writel(0x0, espi->regs + ESPI_MMBI_INT_EN); ++ writel(0xffffffff, espi->regs + ESPI_MMBI_INT_STS); ++ ++ reg = readl(espi->regs + ESPI_CTRL2); ++ reg &= ~(ESPI_CTRL2_MCYC_RD_DIS_WDT | ESPI_CTRL2_MCYC_WR_DIS_WDT); ++ writel(reg, espi->regs + ESPI_CTRL2); ++ ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_PERIF_NP_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_RX_DMA_EN ++ | ESPI_CTRL_PERIF_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ if (perif->mmbi.enable) { ++ reg = readl(espi->regs + ESPI_MMBI_CTRL); ++ reg &= ~(ESPI_MMBI_CTRL_EN); ++ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ ++ mask = ~(perif->mmbi.size - 1); ++ writel(mask, espi->regs + ESPI_PERIF_MMBI_MASK); ++ writel(perif->mmbi.saddr, espi->regs + ESPI_PERIF_MMBI_SADDR); ++ writel(perif->mmbi.taddr, espi->regs + ESPI_PERIF_MMBI_TADDR); ++ ++ writel(0xffffffff, espi->regs + ESPI_MMBI_INT_EN); ++ ++ reg = FIELD_PREP(ESPI_MMBI_CTRL_INST_SZ, perif->mmbi.inst_size) ++ | FIELD_PREP(ESPI_MMBI_CTRL_TOTAL_SZ, perif->mmbi.inst_size) ++ | ESPI_MMBI_CTRL_EN; ++ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ ++ reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_MMBI_RD_DIS | ESPI_CTRL2_MMBI_WR_DIS); ++ writel(reg, espi->regs + ESPI_CTRL2); + } + -+ if (flash->dma.enable) { -+ writel(flash->dma.tx_addr, espi->regs + ESPI_FLASH_TX_DMA); -+ writel(flash->dma.rx_addr, espi->regs + ESPI_FLASH_RX_DMA); ++ if (perif->mcyc.enable) { ++ mask = ~(perif->mcyc.size - 1); ++ writel(mask, espi->regs + ESPI_PERIF_MCYC_MASK); ++ writel(perif->mcyc.saddr, espi->regs + ESPI_PERIF_MCYC_SADDR); ++ writel(perif->mcyc.taddr, espi->regs + ESPI_PERIF_MCYC_TADDR); ++ ++ reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_MCYC_RD_DIS | ESPI_CTRL2_MCYC_WR_DIS); ++ writel(reg, espi->regs + ESPI_CTRL2); ++ } ++ ++ if (perif->dma.enable) { ++ writel(perif->dma.np_tx_addr, espi->regs + ESPI_PERIF_NP_TX_DMA); ++ writel(perif->dma.pc_tx_addr, espi->regs + ESPI_PERIF_PC_TX_DMA); ++ writel(perif->dma.pc_rx_addr, espi->regs + ESPI_PERIF_PC_RX_DMA); + + reg = readl(espi->regs + ESPI_CTRL) -+ | ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN; ++ | ESPI_CTRL_PERIF_NP_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_RX_DMA_EN; + writel(reg, espi->regs + ESPI_CTRL); + } + -+ reg = readl(espi->regs + ESPI_INT_EN) | ESPI_INT_EN_FLASH_RX_CMPLT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++ writel(ESPI_INT_EN_PERIF_PC_RX_CMPLT, espi->regs + ESPI_INT_EN); + -+ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SW_RDY; ++ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_PERIF_SW_RDY; + writel(reg, espi->regs + ESPI_CTRL); +} + -+static int ast2500_espi_flash_probe(struct ast2500_espi *espi) ++int ast2600_espi_perif_probe(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_flash *flash; ++ struct aspeed_espi_perif_mmbi *mmbi; ++ struct aspeed_espi_perif *perif; ++ struct platform_device *pdev; + struct device *dev; -+ int rc; ++ int i, rc; + + dev = espi->dev; + -+ flash = &espi->flash; ++ perif = &espi->perif; + -+ init_waitqueue_head(&flash->wq); ++ init_waitqueue_head(&perif->wq); + -+ spin_lock_init(&flash->lock); ++ spin_lock_init(&perif->lock); + -+ mutex_init(&flash->tx_mtx); -+ mutex_init(&flash->rx_mtx); ++ mutex_init(&perif->np_tx_mtx); ++ mutex_init(&perif->pc_tx_mtx); ++ mutex_init(&perif->pc_rx_mtx); + -+ flash->safs.mode = SAFS_MODE_MIX; ++ perif->mmbi.enable = of_property_read_bool(dev->of_node, "perif-mmbi-enable"); ++ if (perif->mmbi.enable) { ++ pdev = espi->pdev; + -+ of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->safs.mode); -+ if (flash->safs.mode == SAFS_MODE_MIX) { -+ rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", &flash->safs.taddr); -+ if (rc || !IS_ALIGNED(flash->safs.taddr, FLASH_SAFS_ALIGN)) { -+ dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); ++ perif->mmbi.irq = platform_get_irq(pdev, 1); ++ if (perif->mmbi.irq < 0) { ++ dev_err(dev, "cannot get MMBI IRQ number\n"); ++ return -ENODEV; ++ } ++ ++ rc = of_property_read_u32(dev->of_node, "perif-mmbi-src-addr", (u32 *)&perif->mmbi.saddr); ++ if (rc || !IS_ALIGNED(perif->mmbi.saddr, PERIF_MMBI_ALIGN)) { ++ dev_err(dev, "cannot get 64KB-aligned MMBI host address\n"); ++ return -ENODEV; ++ } ++ ++ rc = of_property_read_u32(dev->of_node, "perif-mmbi-instance-size", (u32 *)&perif->mmbi.inst_size); ++ if (rc || perif->mmbi.inst_size >= MMBI_INST_SIZE_TYPES) { ++ dev_err(dev, "cannot get valid MMBI instance size\n"); ++ return -EINVAL; ++ } ++ ++ perif->mmbi.size = (SZ_8K << perif->mmbi.inst_size) * PERIF_MMBI_INST_NUM; ++ perif->mmbi.virt = dmam_alloc_coherent(dev, perif->mmbi.size, ++ &perif->mmbi.taddr, GFP_KERNEL); ++ if (!perif->mmbi.virt) { ++ dev_err(dev, "cannot allocate MMBI\n"); ++ return -ENOMEM; ++ } ++ ++ perif->mmbi.mmbi_isr = ast2600_espi_perif_mmbi_isr; ++ ++ for (i = 0; i < PERIF_MMBI_INST_NUM; ++i) { ++ mmbi = &perif->mmbi.inst[i]; ++ ++ init_waitqueue_head(&mmbi->wq); ++ ++ mmbi->perif = perif; ++ mmbi->host_rwp_update = false; ++ ++ mmbi->b2h_virt = perif->mmbi.virt + ((SZ_4K << perif->mmbi.inst_size) * i); ++ mmbi->b2h_addr = perif->mmbi.taddr + ((SZ_4K << perif->mmbi.inst_size) * i); ++ mmbi->b2h_mdev.parent = dev; ++ mmbi->b2h_mdev.minor = MISC_DYNAMIC_MINOR; ++ mmbi->b2h_mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-mmbi-b2h%d", DEVICE_NAME, i); ++ mmbi->b2h_mdev.fops = &ast2600_espi_mmbi_b2h_fops; ++ rc = misc_register(&mmbi->b2h_mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", mmbi->b2h_mdev.name); ++ return rc; ++ } ++ ++ mmbi->h2b_virt = perif->mmbi.virt + ((SZ_4K << perif->mmbi.inst_size) * (i + PERIF_MMBI_INST_NUM)); ++ mmbi->h2b_addr = perif->mmbi.taddr + ((SZ_4K << perif->mmbi.inst_size) * (i + PERIF_MMBI_INST_NUM)); ++ mmbi->h2b_mdev.parent = dev; ++ mmbi->h2b_mdev.minor = MISC_DYNAMIC_MINOR; ++ mmbi->h2b_mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-mmbi-h2b%d", DEVICE_NAME, i); ++ mmbi->h2b_mdev.fops = &ast2600_espi_mmbi_h2b_fops; ++ rc = misc_register(&mmbi->h2b_mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", mmbi->h2b_mdev.name); ++ return rc; ++ } ++ } ++ } ++ ++ perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); ++ if (perif->mcyc.enable) { ++ if (perif->mmbi.enable) { ++ dev_err(dev, "cannot enable memory cycle, occupied by MMBI\n"); ++ return -EPERM; ++ } ++ ++ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", (u32 *)&perif->mcyc.saddr); ++ if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { ++ dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); + return -ENODEV; + } + -+ rc = of_property_read_u32(dev->of_node, "flash-safs-size", &flash->safs.size); -+ if (rc || !IS_ALIGNED(flash->safs.size, FLASH_SAFS_ALIGN)) { -+ dev_err(dev, "cannot get 16MB-aligned SAFS size\n"); -+ return -ENODEV; ++ rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", (u32 *)&perif->mcyc.size); ++ if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { ++ dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); ++ return -EINVAL; ++ } ++ ++ perif->mcyc.virt = dmam_alloc_coherent(dev, perif->mcyc.size, ++ &perif->mcyc.taddr, GFP_KERNEL); ++ if (!perif->mcyc.virt) { ++ dev_err(dev, "cannot allocate memory cycle\n"); ++ return -ENOMEM; + } + } + -+ flash->dma.enable = of_property_read_bool(dev->of_node, "flash-dma-mode"); -+ if (flash->dma.enable) { -+ flash->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.tx_addr, GFP_KERNEL); -+ if (!flash->dma.tx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ perif->dma.enable = of_property_read_bool(dev->of_node, "perif-dma-mode"); ++ if (perif->dma.enable) { ++ perif->dma.pc_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, ++ &perif->dma.pc_tx_addr, GFP_KERNEL); ++ if (!perif->dma.pc_tx_virt) { ++ dev_err(dev, "cannot allocate posted TX DMA buffer\n"); + return -ENOMEM; + } + -+ flash->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.rx_addr, GFP_KERNEL); -+ if (!flash->dma.rx_virt) { -+ dev_err(dev, "cannot allocate DMA RX buffer\n"); ++ perif->dma.pc_rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, ++ &perif->dma.pc_rx_addr, GFP_KERNEL); ++ if (!perif->dma.pc_rx_virt) { ++ dev_err(dev, "cannot allocate posted RX DMA buffer\n"); ++ return -ENOMEM; ++ } ++ ++ perif->dma.np_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, ++ &perif->dma.np_tx_addr, GFP_KERNEL); ++ if (!perif->dma.np_tx_virt) { ++ dev_err(dev, "cannot allocate non-posted TX DMA buffer\n"); + return -ENOMEM; + } + } + -+ flash->mdev.parent = dev; -+ flash->mdev.minor = MISC_DYNAMIC_MINOR; -+ flash->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-flash", DEVICE_NAME); -+ flash->mdev.fops = &ast2500_espi_flash_fops; -+ rc = misc_register(&flash->mdev); ++ perif->mdev.parent = dev; ++ perif->mdev.minor = MISC_DYNAMIC_MINOR; ++ perif->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-peripheral", DEVICE_NAME); ++ perif->mdev.fops = &ast2600_espi_perif_fops; ++ rc = misc_register(&perif->mdev); + if (rc) { -+ dev_err(dev, "cannot register device %s\n", flash->mdev.name); ++ dev_err(dev, "cannot register device %s\n", perif->mdev.name); + return rc; + } + -+ ast2500_espi_flash_reset(espi); ++ ast2600_espi_perif_reset(espi); + + return 0; +} + -+static int ast2500_espi_flash_remove(struct ast2500_espi *espi) ++int ast2600_espi_perif_remove(struct aspeed_espi *espi) +{ -+ struct ast2500_espi_flash *flash; ++ struct aspeed_espi_perif_mmbi *mmbi; ++ struct aspeed_espi_perif *perif; + struct device *dev; -+ uint32_t reg; ++ u32 reg; ++ int i; + + dev = espi->dev; + -+ flash = &espi->flash; ++ perif = &espi->perif; + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~(ESPI_INT_EN_FLASH); -+ writel(reg, espi->regs + ESPI_INT_EN); ++ writel(ESPI_INT_EN_PERIF, espi->regs + ESPI_INT_EN_CLR); ++ ++ reg = readl(espi->regs + ESPI_CTRL2); ++ reg |= (ESPI_CTRL2_MCYC_RD_DIS | ESPI_CTRL2_MCYC_WR_DIS); ++ writel(reg, espi->regs + ESPI_CTRL2); + + reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN -+ | ESPI_CTRL_FLASH_SW_RDY); ++ reg &= ~(ESPI_CTRL_PERIF_NP_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_TX_DMA_EN ++ | ESPI_CTRL_PERIF_PC_RX_DMA_EN ++ | ESPI_CTRL_PERIF_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + -+ if (flash->dma.enable) { -+ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.rx_addr); ++ if (perif->mmbi.enable) { ++ reg = readl(espi->regs + ESPI_MMBI_CTRL); ++ reg &= ~ESPI_MMBI_CTRL_EN; ++ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ ++ for (i = 0; i < PERIF_MMBI_INST_NUM; ++i) { ++ mmbi = &perif->mmbi.inst[i]; ++ misc_deregister(&mmbi->b2h_mdev); ++ misc_deregister(&mmbi->h2b_mdev); ++ } ++ ++ dmam_free_coherent(dev, perif->mmbi.size, perif->mmbi.virt, ++ perif->mmbi.taddr); + } + -+ mutex_destroy(&flash->tx_mtx); -+ mutex_destroy(&flash->rx_mtx); ++ if (perif->mcyc.enable) ++ dmam_free_coherent(dev, perif->mcyc.size, perif->mcyc.virt, ++ perif->mcyc.taddr); + -+ misc_deregister(&flash->mdev); ++ if (perif->dma.enable) { ++ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.np_tx_virt, ++ perif->dma.np_tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_tx_virt, ++ perif->dma.pc_tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_rx_virt, ++ perif->dma.pc_rx_addr); ++ } ++ ++ mutex_destroy(&perif->np_tx_mtx); ++ mutex_destroy(&perif->pc_tx_mtx); ++ mutex_destroy(&perif->pc_rx_mtx); ++ ++ misc_deregister(&perif->mdev); + + return 0; +} + -+/* global control */ -+static irqreturn_t ast2500_espi_isr(int irq, void *arg) ++/* virtual wire channel (CH1) */ ++static long ast2600_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2500_espi *espi; -+ uint32_t sts; ++ struct aspeed_espi_vw *vw; ++ struct aspeed_espi *espi; ++ u32 gpio, hw_mode; + -+ espi = (struct ast2500_espi *)arg; ++ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); ++ espi = container_of(vw, struct aspeed_espi, vw); ++ gpio = vw->gpio.val0; ++ hw_mode = vw->gpio.hw_mode; + -+ sts = readl(espi->regs + ESPI_INT_STS); -+ if (!sts) -+ return IRQ_NONE; ++ if (hw_mode) { ++ dev_err(espi->dev, "HW mode: vGPIO reflect on physical GPIO. Get state from GPIO driver.\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_PERIF) -+ ast2500_espi_perif_isr(espi); ++ switch (cmd) { ++ case ASPEED_ESPI_VW_GET_GPIO_VAL: ++ if (put_user(gpio, (u32 __user *)arg)) { ++ dev_err(espi->dev, "failed to get vGPIO value\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_VW) -+ ast2500_espi_vw_isr(espi); ++ dev_info(espi->dev, "Get vGPIO value: 0x%x\n", gpio); ++ break; + -+ if (sts & ESPI_INT_STS_OOB) -+ ast2500_espi_oob_isr(espi); ++ case ASPEED_ESPI_VW_PUT_GPIO_VAL: ++ if (get_user(gpio, (u32 __user *)arg)) { ++ dev_err(espi->dev, "failed to put vGPIO value\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_FLASH) -+ ast2500_espi_flash_isr(espi); ++ dev_info(espi->dev, "Put vGPIO value: 0x%x\n", gpio); ++ writel(gpio, espi->regs + ESPI_VW_GPIO_VAL); ++ break; + -+ if (sts & ESPI_INT_STS_RST_DEASSERT) { -+ ast2500_espi_perif_reset(espi); -+ ast2500_espi_vw_reset(espi); -+ ast2500_espi_oob_reset(espi); -+ ast2500_espi_flash_reset(espi); -+ writel(ESPI_INT_STS_RST_DEASSERT, espi->regs + ESPI_INT_STS); -+ } ++ default: ++ return -EINVAL; ++ }; + -+ return IRQ_HANDLED; ++ return 0; +} + -+static int ast2500_espi_probe(struct platform_device *pdev) -+{ -+ struct ast2500_espi *espi; -+ struct resource *res; -+ struct device *dev; -+ uint32_t reg; -+ int rc; ++static const struct file_operations ast2600_espi_vw_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2600_espi_vw_ioctl, ++}; + -+ dev = &pdev->dev; ++static void ast2600_espi_vw_isr(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_vw *vw; ++ u32 sts; + -+ espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -+ if (!espi) -+ return -ENOMEM; ++ vw = &espi->vw; + -+ espi->dev = dev; ++ sts = readl(espi->regs + ESPI_INT_STS); + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; ++ if (sts & ESPI_INT_STS_VW_GPIO) { ++ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ writel(ESPI_INT_STS_VW_GPIO, espi->regs + ESPI_INT_STS); ++ } else if (sts & ESPI_INT_STS_VW_SYSEVT) { ++ /* Handle system event */ ++ writel(ESPI_INT_STS_VW_SYSEVT, espi->regs + ESPI_INT_STS); ++ } else if (sts & (ESPI_INT_STS_VW_SYSEVT1)) { ++ /* Handle system event1 */ ++ writel(ESPI_INT_STS_VW_SYSEVT1, espi->regs + ESPI_INT_STS); + } ++} + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(dev, "cannot get resource\n"); -+ return -ENODEV; -+ } ++static void ast2600_espi_vw_reset(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ struct aspeed_espi_vw *vw = &espi->vw; + -+ espi->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(espi->regs)) { -+ dev_err(dev, "cannot map registers\n"); -+ return PTR_ERR(espi->regs); -+ } ++ writel(ESPI_INT_EN_VW, espi->regs + ESPI_INT_EN_CLR); ++ writel(ESPI_INT_STS_VW, espi->regs + ESPI_INT_STS); + -+ espi->irq = platform_get_irq(pdev, 0); -+ if (espi->irq < 0) { -+ dev_err(dev, "cannot get IRQ number\n"); -+ return -ENODEV; -+ } ++ writel(vw->gpio.dir0, espi->regs + ESPI_VW_GPIO_DIR); + -+ espi->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(espi->clk)) { -+ dev_err(dev, "cannot get clock control\n"); -+ return PTR_ERR(espi->clk); -+ } ++ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); + -+ rc = clk_prepare_enable(espi->clk); -+ if (rc) { -+ dev_err(dev, "cannot enable clocks\n"); -+ return rc; -+ } ++ reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_VW_TX_SORT); ++ writel(reg, espi->regs + ESPI_CTRL2); ++ ++ writel(ESPI_INT_EN_VW_GPIO, espi->regs + ESPI_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CTRL) ++ | ((vw->gpio.hw_mode) ? 0 : ESPI_CTRL_VW_GPIO_SW) ++ | ESPI_CTRL_VW_SW_RDY; ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_T0); ++ writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_T1); + + reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~ESPI_INT_EN_RST_DEASSERT; ++ reg |= ESPI_INT_EN_RST_DEASSERT; + writel(reg, espi->regs + ESPI_INT_EN); + -+ rc = ast2500_espi_perif_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); -+ return rc; -+ } ++ writel(0xffffffff, espi->regs + ESPI_VW_SYSEVT_INT_EN); ++ writel(0x1, espi->regs + ESPI_VW_SYSEVT1_INT_EN); ++ writel(0x1, espi->regs + ESPI_VW_SYSEVT1_INT_T0); ++} + -+ rc = ast2500_espi_vw_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init vw channel, rc=%d\n", rc); -+ goto err_remove_perif; -+ } ++int ast2600_espi_vw_probe(struct aspeed_espi *espi) ++{ ++ int rc; ++ struct device *dev = espi->dev; ++ struct aspeed_espi_vw *vw = &espi->vw; + -+ rc = ast2500_espi_oob_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init oob channel, rc=%d\n", rc); -+ goto err_remove_vw; -+ } ++ vw->gpio.hw_mode = of_property_read_bool(dev->of_node, "vw-gpio-hw-mode"); ++ of_property_read_u32(dev->of_node, "vw-gpio-direction", &vw->gpio.dir0); + -+ rc = ast2500_espi_flash_probe(espi); ++ vw->mdev.parent = dev; ++ vw->mdev.minor = MISC_DYNAMIC_MINOR; ++ vw->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-vw", DEVICE_NAME); ++ vw->mdev.fops = &ast2600_espi_vw_fops; ++ rc = misc_register(&vw->mdev); + if (rc) { -+ dev_err(dev, "cannot init flash channel, rc=%d\n", rc); -+ goto err_remove_oob; ++ dev_err(dev, "cannot register device %s\n", vw->mdev.name); ++ return rc; + } + -+ rc = devm_request_irq(dev, espi->irq, ast2500_espi_isr, 0, dev_name(dev), espi); -+ if (rc) { -+ dev_err(dev, "cannot request IRQ\n"); -+ goto err_remove_flash; -+ } ++ ast2600_espi_vw_reset(espi); + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg |= ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++ return 0; ++} + -+ dev_set_drvdata(dev, espi); ++int ast2600_espi_vw_remove(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_vw *vw; + -+ dev_info(dev, "module loaded\n"); ++ vw = &espi->vw; + -+ return 0; ++ writel(ESPI_INT_EN_VW, espi->regs + ESPI_INT_EN_CLR); + -+err_remove_flash: -+ ast2500_espi_flash_remove(espi); -+err_remove_oob: -+ ast2500_espi_oob_remove(espi); -+err_remove_vw: -+ ast2500_espi_vw_remove(espi); -+err_remove_perif: -+ ast2500_espi_perif_remove(espi); ++ misc_deregister(&vw->mdev); + -+ return rc; ++ return 0; +} + -+static int ast2500_espi_remove(struct platform_device *pdev) ++/* out-of-band channel (CH2) */ ++static long ast2600_espi_oob_dma_get_rx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) +{ -+ struct ast2500_espi *espi; -+ struct device *dev; -+ uint32_t reg; ++ struct ast2600_espi_oob_dma_rx_desc *d; ++ struct ast2600_espi_oob_dma_rx_desc *rx_descs; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u32 wptr, pkt_len; ++ unsigned long flags; ++ u8 *pkt; + int rc; + -+ dev = &pdev->dev; ++ espi = container_of(oob, struct aspeed_espi, oob); + -+ espi = (struct ast2500_espi *)dev_get_drvdata(dev); ++ wptr = FIELD_PREP(ESPI_OOB_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_OOB_RX_DESC_WPTR)); + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~(ESPI_INT_EN_RST_DEASSERT); -+ writel(reg, espi->regs + ESPI_INT_EN); ++ rx_descs = (struct ast2600_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; ++ d = &rx_descs[wptr]; + -+ rc = ast2500_espi_perif_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ if (!d->dirty) ++ return -EFAULT; + -+ rc = ast2500_espi_vw_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ pkt_len = ((d->len) ? d->len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); + -+ rc = ast2500_espi_oob_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ if (ioc->pkt_len < pkt_len) ++ return -EINVAL; + -+ rc = ast2500_espi_flash_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ pkt = vmalloc(pkt_len); ++ if (!pkt) ++ return -ENOMEM; + -+ return 0; -+} ++ hdr = (struct espi_comm_hdr *)pkt; ++ hdr->cyc = d->cyc; ++ hdr->tag = d->tag; ++ hdr->len_h = d->len >> 8; ++ hdr->len_l = d->len & 0xff; ++ memcpy(hdr + 1, oob->dma.rx_virt + (PAGE_SIZE * wptr), pkt_len - sizeof(*hdr)); + -+static const struct of_device_id ast2500_espi_of_matches[] = { -+ { .compatible = "aspeed,ast2500-espi" }, -+ { }, -+}; ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+static struct platform_driver ast2500_espi_driver = { -+ .driver = { -+ .name = "ast2500-espi", -+ .of_match_table = ast2500_espi_of_matches, -+ }, -+ .probe = ast2500_espi_probe, -+ .remove = ast2500_espi_remove, -+}; ++ spin_lock_irqsave(&oob->lock, flags); + -+module_platform_driver(ast2500_espi_driver); ++ /* make current descriptor available again */ ++ d->dirty = 0; + -+MODULE_AUTHOR("Chia-Wei Wang "); -+MODULE_DESCRIPTION("Control of AST2500 eSPI Device"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2500-espi.h b/drivers/soc/aspeed/ast2500-espi.h ---- a/drivers/soc/aspeed/ast2500-espi.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2500-espi.h 2025-12-23 10:16:21.126032636 +0000 -@@ -0,0 +1,250 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#ifndef _AST2500_ESPI_H_ -+#define _AST2500_ESPI_H_ ++ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; ++ writel(wptr | ESPI_OOB_RX_DESC_WPTR_RECV_EN, espi->regs + ESPI_OOB_RX_DESC_WPTR); + -+#include -+#include "aspeed-espi-comm.h" ++ /* set ready flag base on the next RX descriptor */ ++ oob->rx_ready = rx_descs[wptr].dirty; + -+/* registers */ -+#define ESPI_CTRL 0x000 -+#define ESPI_CTRL_FLASH_TX_SW_RST BIT(31) -+#define ESPI_CTRL_FLASH_RX_SW_RST BIT(30) -+#define ESPI_CTRL_OOB_TX_SW_RST BIT(29) -+#define ESPI_CTRL_OOB_RX_SW_RST BIT(28) -+#define ESPI_CTRL_PERIF_NP_TX_SW_RST BIT(27) -+#define ESPI_CTRL_PERIF_NP_RX_SW_RST BIT(26) -+#define ESPI_CTRL_PERIF_PC_TX_SW_RST BIT(25) -+#define ESPI_CTRL_PERIF_PC_RX_SW_RST BIT(24) -+#define ESPI_CTRL_FLASH_TX_DMA_EN BIT(23) -+#define ESPI_CTRL_FLASH_RX_DMA_EN BIT(22) -+#define ESPI_CTRL_OOB_TX_DMA_EN BIT(21) -+#define ESPI_CTRL_OOB_RX_DMA_EN BIT(20) -+#define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) -+#define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) -+#define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) -+#define ESPI_CTRL_FLASH_SAFS_SW_MODE BIT(10) -+#define ESPI_CTRL_VW_GPIO_SW BIT(9) -+#define ESPI_CTRL_FLASH_SW_RDY BIT(7) -+#define ESPI_CTRL_OOB_SW_RDY BIT(4) -+#define ESPI_CTRL_VW_SW_RDY BIT(3) -+#define ESPI_CTRL_PERIF_SW_RDY BIT(1) -+#define ESPI_STS 0x004 -+#define ESPI_INT_STS 0x008 -+#define ESPI_INT_STS_RST_DEASSERT BIT(31) -+#define ESPI_INT_STS_OOB_RX_TMOUT BIT(23) -+#define ESPI_INT_STS_VW_SYSEVT1 BIT(22) -+#define ESPI_INT_STS_FLASH_TX_ERR BIT(21) -+#define ESPI_INT_STS_OOB_TX_ERR BIT(20) -+#define ESPI_INT_STS_FLASH_TX_ABT BIT(19) -+#define ESPI_INT_STS_OOB_TX_ABT BIT(18) -+#define ESPI_INT_STS_PERIF_NP_TX_ABT BIT(17) -+#define ESPI_INT_STS_PERIF_PC_TX_ABT BIT(16) -+#define ESPI_INT_STS_FLASH_RX_ABT BIT(15) -+#define ESPI_INT_STS_OOB_RX_ABT BIT(14) -+#define ESPI_INT_STS_PERIF_NP_RX_ABT BIT(13) -+#define ESPI_INT_STS_PERIF_PC_RX_ABT BIT(12) -+#define ESPI_INT_STS_PERIF_NP_TX_ERR BIT(11) -+#define ESPI_INT_STS_PERIF_PC_TX_ERR BIT(10) -+#define ESPI_INT_STS_VW_GPIO BIT(9) -+#define ESPI_INT_STS_VW_SYSEVT BIT(8) -+#define ESPI_INT_STS_FLASH_TX_CMPLT BIT(7) -+#define ESPI_INT_STS_FLASH_RX_CMPLT BIT(6) -+#define ESPI_INT_STS_OOB_TX_CMPLT BIT(5) -+#define ESPI_INT_STS_OOB_RX_CMPLT BIT(4) -+#define ESPI_INT_STS_PERIF_NP_TX_CMPLT BIT(3) -+#define ESPI_INT_STS_PERIF_PC_TX_CMPLT BIT(1) -+#define ESPI_INT_STS_PERIF_PC_RX_CMPLT BIT(0) -+#define ESPI_INT_EN 0x00c -+#define ESPI_INT_EN_RST_DEASSERT BIT(31) -+#define ESPI_INT_EN_OOB_RX_TMOUT BIT(23) -+#define ESPI_INT_EN_VW_SYSEVT1 BIT(22) -+#define ESPI_INT_EN_FLASH_TX_ERR BIT(21) -+#define ESPI_INT_EN_OOB_TX_ERR BIT(20) -+#define ESPI_INT_EN_FLASH_TX_ABT BIT(19) -+#define ESPI_INT_EN_OOB_TX_ABT BIT(18) -+#define ESPI_INT_EN_PERIF_NP_TX_ABT BIT(17) -+#define ESPI_INT_EN_PERIF_PC_TX_ABT BIT(16) -+#define ESPI_INT_EN_FLASH_RX_ABT BIT(15) -+#define ESPI_INT_EN_OOB_RX_ABT BIT(14) -+#define ESPI_INT_EN_PERIF_NP_RX_ABT BIT(13) -+#define ESPI_INT_EN_PERIF_PC_RX_ABT BIT(12) -+#define ESPI_INT_EN_PERIF_NP_TX_ERR BIT(11) -+#define ESPI_INT_EN_PERIF_PC_TX_ERR BIT(10) -+#define ESPI_INT_EN_VW_GPIO BIT(9) -+#define ESPI_INT_EN_VW_SYSEVT BIT(8) -+#define ESPI_INT_EN_FLASH_TX_CMPLT BIT(7) -+#define ESPI_INT_EN_FLASH_RX_CMPLT BIT(6) -+#define ESPI_INT_EN_OOB_TX_CMPLT BIT(5) -+#define ESPI_INT_EN_OOB_RX_CMPLT BIT(4) -+#define ESPI_INT_EN_PERIF_NP_TX_CMPLT BIT(3) -+#define ESPI_INT_EN_PERIF_PC_TX_CMPLT BIT(1) -+#define ESPI_INT_EN_PERIF_PC_RX_CMPLT BIT(0) -+#define ESPI_PERIF_PC_RX_DMA 0x010 -+#define ESPI_PERIF_PC_RX_CTRL 0x014 -+#define ESPI_PERIF_PC_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_PERIF_PC_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_PERIF_PC_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_PERIF_PC_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_PERIF_PC_RX_DATA 0x018 -+#define ESPI_PERIF_PC_TX_DMA 0x020 -+#define ESPI_PERIF_PC_TX_CTRL 0x024 -+#define ESPI_PERIF_PC_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_PERIF_PC_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_PERIF_PC_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_PERIF_PC_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_PERIF_PC_TX_DATA 0x028 -+#define ESPI_PERIF_NP_TX_DMA 0x030 -+#define ESPI_PERIF_NP_TX_CTRL 0x034 -+#define ESPI_PERIF_NP_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_PERIF_NP_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_PERIF_NP_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_PERIF_NP_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_PERIF_NP_TX_DATA 0x038 -+#define ESPI_OOB_RX_DMA 0x040 -+#define ESPI_OOB_RX_CTRL 0x044 -+#define ESPI_OOB_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_OOB_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_OOB_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_OOB_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_OOB_RX_DATA 0x048 -+#define ESPI_OOB_TX_DMA 0x050 -+#define ESPI_OOB_TX_CTRL 0x054 -+#define ESPI_OOB_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_OOB_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_OOB_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_OOB_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_OOB_TX_DATA 0x058 -+#define ESPI_FLASH_RX_DMA 0x060 -+#define ESPI_FLASH_RX_CTRL 0x064 -+#define ESPI_FLASH_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_FLASH_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_FLASH_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_FLASH_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_FLASH_RX_DATA 0x068 -+#define ESPI_FLASH_TX_DMA 0x070 -+#define ESPI_FLASH_TX_CTRL 0x074 -+#define ESPI_FLASH_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_FLASH_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_FLASH_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_FLASH_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_FLASH_TX_DATA 0x078 -+#define ESPI_PERIF_MCYC_SADDR 0x084 -+#define ESPI_PERIF_MCYC_TADDR 0x088 -+#define ESPI_PERIF_MCYC_MASK 0x08c -+#define ESPI_FLASH_SAFS_TADDR 0x090 -+#define ESPI_FLASH_SAFS_TADDR_BASE GENMASK(31, 24) -+#define ESPI_FLASH_SAFS_TADDR_MASK GENMASK(15, 8) -+#define ESPI_VW_SYSEVT_INT_EN 0x094 -+#define ESPI_VW_SYSEVT_INT_EN_HOST_RST_WARN BIT(8) -+#define ESPI_VW_SYSEVT_INT_EN_OOB_RST_WARN BIT(6) -+#define ESPI_VW_SYSEVT 0x098 -+#define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) -+#define ESPI_VW_SYSEVT_SLV_BOOT_STS BIT(23) -+#define ESPI_VW_SYSEVT_SLV_BOOT_DONE BIT(20) -+#define ESPI_VW_SYSEVT_OOB_RST_ACK BIT(16) -+#define ESPI_VW_SYSEVT_HOST_RST_WARN BIT(8) -+#define ESPI_VW_SYSEVT_OOB_RST_WARN BIT(6) -+#define ESPI_VW_GPIO_VAL 0x09c -+#define ESPI_GEN_CAP_N_CONF 0x0a0 -+#define ESPI_CH0_CAP_N_CONF 0x0a4 -+#define ESPI_CH1_CAP_N_CONF 0x0a8 -+#define ESPI_CH2_CAP_N_CONF 0x0ac -+#define ESPI_CH3_CAP_N_CONF 0x0b0 -+#define ESPI_CH3_CAP_N_CONF2 0x0b4 -+#define ESPI_VW_GPIO_DIR 0x0c0 -+#define ESPI_VW_GPIO_GRP 0x0c4 -+#define ESPI_VW_SYSEVT1_INT_EN 0x100 -+#define ESPI_VW_SYSEVT1_INT_EN_SUSPEND_WARN BIT(0) -+#define ESPI_VW_SYSEVT1 0x104 -+#define ESPI_VW_SYSEVT1_SUSPEND_ACK BIT(20) -+#define ESPI_VW_SYSEVT1_SUSPEND_WARN BIT(0) -+#define ESPI_VW_SYSEVT_INT_T0 0x110 -+#define ESPI_VW_SYSEVT_INT_T1 0x114 -+#define ESPI_VW_SYSEVT_INT_T2 0x118 -+#define ESPI_VW_SYSEVT_INT_T2_HOST_RST_WARN BIT(8) -+#define ESPI_VW_SYSEVT_INT_T2_OOB_RST_WARN BIT(6) -+#define ESPI_VW_SYSEVT_INT_STS 0x11c -+#define ESPI_VW_SYSEVT_INT_STS_HOST_RST_WARN BIT(8) -+#define ESPI_VW_SYSEVT_INT_STS_OOB_RST_WARN BIT(6) -+#define ESPI_VW_SYSEVT1_INT_T0 0x120 -+#define ESPI_VW_SYSEVT1_INT_T0_SUSPEND_WARN BIT(0) -+#define ESPI_VW_SYSEVT1_INT_T1 0x124 -+#define ESPI_VW_SYSEVT1_INT_T2 0x128 -+#define ESPI_VW_SYSEVT1_INT_STS 0x12c -+#define ESPI_VW_SYSEVT1_INT_STS_SUSPEND_WARN BIT(0) ++ spin_unlock_irqrestore(&oob->lock, flags); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++ return rc; ++} ++ ++static long ast2600_espi_oob_get_rx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ unsigned long flags; ++ u32 pkt_len; ++ u8 *pkt; ++ int i, rc; + -+/* collect ESPI_INT_EN bits for convenience */ -+#define ESPI_INT_EN_PERIF \ -+ (ESPI_INT_EN_PERIF_NP_TX_ABT | \ -+ ESPI_INT_EN_PERIF_PC_TX_ABT | \ -+ ESPI_INT_EN_PERIF_NP_RX_ABT | \ -+ ESPI_INT_EN_PERIF_PC_RX_ABT | \ -+ ESPI_INT_EN_PERIF_NP_TX_ERR | \ -+ ESPI_INT_EN_PERIF_PC_TX_ERR | \ -+ ESPI_INT_EN_PERIF_NP_TX_CMPLT | \ -+ ESPI_INT_EN_PERIF_PC_TX_CMPLT | \ -+ ESPI_INT_EN_PERIF_PC_RX_CMPLT) ++ espi = container_of(oob, struct aspeed_espi, oob); + -+#define ESPI_INT_EN_VW \ -+ (ESPI_INT_EN_VW_SYSEVT1 | \ -+ ESPI_INT_EN_VW_GPIO | \ -+ ESPI_INT_EN_VW_SYSEVT) ++ if (fp->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&oob->rx_mtx)) ++ return -EAGAIN; + -+#define ESPI_INT_EN_OOB \ -+ (ESPI_INT_EN_OOB_RX_TMOUT | \ -+ ESPI_INT_EN_OOB_TX_ERR | \ -+ ESPI_INT_EN_OOB_TX_ABT | \ -+ ESPI_INT_EN_OOB_RX_ABT | \ -+ ESPI_INT_EN_OOB_TX_CMPLT | \ -+ ESPI_INT_EN_OOB_RX_CMPLT) ++ if (!oob->rx_ready) { ++ rc = -ENODATA; ++ goto unlock_mtx_n_out; ++ } ++ } else { ++ mutex_lock(&oob->rx_mtx); + -+#define ESPI_INT_EN_FLASH \ -+ (ESPI_INT_EN_FLASH_TX_ERR | \ -+ ESPI_INT_EN_FLASH_TX_ABT | \ -+ ESPI_INT_EN_FLASH_RX_ABT | \ -+ ESPI_INT_EN_FLASH_TX_CMPLT | \ -+ ESPI_INT_EN_FLASH_RX_CMPLT) ++ if (!oob->rx_ready) { ++ rc = wait_event_interruptible(oob->wq, oob->rx_ready); ++ if (rc == -ERESTARTSYS) { ++ rc = -EINTR; ++ goto unlock_mtx_n_out; ++ } ++ } ++ } + -+/* collect ESPI_INT_STS bits for convenience */ -+#define ESPI_INT_STS_PERIF \ -+ (ESPI_INT_STS_PERIF_NP_TX_ABT | \ -+ ESPI_INT_STS_PERIF_PC_TX_ABT | \ -+ ESPI_INT_STS_PERIF_NP_RX_ABT | \ -+ ESPI_INT_STS_PERIF_PC_RX_ABT | \ -+ ESPI_INT_STS_PERIF_NP_TX_ERR | \ -+ ESPI_INT_STS_PERIF_PC_TX_ERR | \ -+ ESPI_INT_STS_PERIF_NP_TX_CMPLT | \ -+ ESPI_INT_STS_PERIF_PC_TX_CMPLT | \ -+ ESPI_INT_STS_PERIF_PC_RX_CMPLT) ++ if (oob->dma.enable) { ++ rc = ast2600_espi_oob_dma_get_rx(fp, oob, ioc); ++ goto unlock_mtx_n_out; ++ } + -+#define ESPI_INT_STS_VW \ -+ (ESPI_INT_STS_VW_SYSEVT1 | \ -+ ESPI_INT_STS_VW_GPIO | \ -+ ESPI_INT_STS_VW_SYSEVT) ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ reg = readl(espi->regs + ESPI_OOB_RX_CTRL); ++ cyc = FIELD_GET(ESPI_OOB_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_OOB_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_OOB_RX_CTRL_LEN, reg); + -+#define ESPI_INT_STS_OOB \ -+ (ESPI_INT_STS_OOB_RX_TMOUT | \ -+ ESPI_INT_STS_OOB_TX_ERR | \ -+ ESPI_INT_STS_OOB_TX_ABT | \ -+ ESPI_INT_STS_OOB_RX_ABT | \ -+ ESPI_INT_STS_OOB_TX_CMPLT | \ -+ ESPI_INT_STS_OOB_RX_CMPLT) ++ /* ++ * calculate the length of the rest part of the ++ * eSPI packet to be read from HW and copied to ++ * user space. ++ */ ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); + -+#define ESPI_INT_STS_FLASH \ -+ (ESPI_INT_STS_FLASH_TX_ERR | \ -+ ESPI_INT_STS_FLASH_TX_ABT | \ -+ ESPI_INT_STS_FLASH_RX_ABT | \ -+ ESPI_INT_STS_FLASH_TX_CMPLT | \ -+ ESPI_INT_STS_FLASH_RX_CMPLT) ++ if (ioc->pkt_len < pkt_len) { ++ rc = -EINVAL; ++ goto unlock_mtx_n_out; ++ } + -+/* consistent with DTS property "flash-safs-mode" */ -+enum ast2500_safs_mode { -+ SAFS_MODE_MIX = 0x0, -+ SAFS_MODE_SW, -+ SAFS_MODES, -+}; ++ pkt = vmalloc(pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; ++ } + -+#endif -diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi.c ---- a/drivers/soc/aspeed/ast2600-espi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2600-espi.c 2025-12-23 10:16:21.126032636 +0000 -@@ -0,0 +1,2188 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ hdr = (struct espi_comm_hdr *)pkt; ++ hdr->cyc = cyc; ++ hdr->tag = tag; ++ hdr->len_h = len >> 8; ++ hdr->len_l = len & 0xff; + -+#include "ast2600-espi.h" ++ for (i = sizeof(*hdr); i < pkt_len; ++i) ++ pkt[i] = readl(espi->regs + ESPI_OOB_RX_DATA) & 0xff; + -+#define DEVICE_NAME "aspeed-espi" ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+#define PERIF_MCYC_ALIGN SZ_64K -+#define PERIF_MMBI_ALIGN SZ_64K -+#define PERIF_MMBI_INST_NUM 8 ++ spin_lock_irqsave(&oob->lock, flags); + -+#define OOB_DMA_RPTR_KEY 0x45538073 -+#define OOB_DMA_DESC_NUM 8 -+#define OOB_DMA_DESC_CUSTOM 0x4 ++ writel(ESPI_OOB_RX_CTRL_SERV_PEND, espi->regs + ESPI_OOB_RX_CTRL); ++ oob->rx_ready = 0; + -+#define FLASH_SAFS_ALIGN SZ_16M ++ spin_unlock_irqrestore(&oob->lock, flags); + -+struct ast2600_espi_perif_mmbi { -+ void *b2h_virt; -+ void *h2b_virt; -+ dma_addr_t b2h_addr; -+ dma_addr_t h2b_addr; -+ struct miscdevice b2h_mdev; -+ struct miscdevice h2b_mdev; -+ bool host_rwp_update; -+ wait_queue_head_t wq; -+ struct ast2600_espi_perif *perif; -+}; ++ rc = 0; + -+struct ast2600_espi_perif { -+ struct { -+ bool enable; -+ int irq; -+ void *virt; -+ dma_addr_t taddr; -+ uint32_t saddr; -+ uint32_t size; -+ uint32_t inst_size; -+ struct ast2600_espi_perif_mmbi inst[PERIF_MMBI_INST_NUM]; -+ } mmbi; ++free_n_out: ++ vfree(pkt); + -+ struct { -+ bool enable; -+ void *virt; -+ dma_addr_t taddr; -+ uint32_t saddr; -+ uint32_t size; -+ } mcyc; ++unlock_mtx_n_out: ++ mutex_unlock(&oob->rx_mtx); + -+ struct { -+ bool enable; -+ void *np_tx_virt; -+ dma_addr_t np_tx_addr; -+ void *pc_tx_virt; -+ dma_addr_t pc_tx_addr; -+ void *pc_rx_virt; -+ dma_addr_t pc_rx_addr; -+ } dma; ++ return rc; ++} + -+ bool rx_ready; -+ wait_queue_head_t wq; ++static long ast2600_espi_oob_dma_put_tx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ struct ast2600_espi_oob_dma_tx_desc *d; ++ struct ast2600_espi_oob_dma_tx_desc *tx_descs; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u32 rptr, wptr; ++ u8 *pkt; ++ int rc; + -+ spinlock_t lock; -+ struct mutex np_tx_mtx; -+ struct mutex pc_tx_mtx; -+ struct mutex pc_rx_mtx; ++ espi = container_of(oob, struct aspeed_espi, oob); + -+ struct miscdevice mdev; -+}; ++ pkt = vzalloc(ioc->pkt_len); ++ if (!pkt) ++ return -ENOMEM; + -+struct ast2600_espi_vw { -+ struct { -+ bool hw_mode; -+ uint32_t dir; -+ uint32_t val; -+ } gpio; ++ hdr = (struct espi_comm_hdr *)pkt; + -+ struct miscdevice mdev; -+}; ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+struct ast2600_espi_oob_dma_tx_desc { -+ uint32_t data_addr; -+ uint8_t cyc; -+ uint16_t tag : 4; -+ uint16_t len : 12; -+ uint8_t msg_type : 3; -+ uint8_t raz0 : 1; -+ uint8_t pec : 1; -+ uint8_t int_en : 1; -+ uint8_t pause : 1; -+ uint8_t raz1 : 1; -+ uint32_t raz2; -+ uint32_t raz3; -+} __packed; ++ /* kick HW to update descriptor read/write pointer */ ++ writel(ESPI_OOB_TX_DESC_RPTR_UPDATE, espi->regs + ESPI_OOB_TX_DESC_RPTR); + -+struct ast2600_espi_oob_dma_rx_desc { -+ uint32_t data_addr; -+ uint8_t cyc; -+ uint16_t tag : 4; -+ uint16_t len : 12; -+ uint8_t raz : 7; -+ uint8_t dirty : 1; -+} __packed; ++ rptr = readl(espi->regs + ESPI_OOB_TX_DESC_RPTR); ++ wptr = readl(espi->regs + ESPI_OOB_TX_DESC_WPTR); + -+struct ast2600_espi_oob { -+ struct { -+ bool enable; -+ struct ast2600_espi_oob_dma_tx_desc *txd_virt; -+ dma_addr_t txd_addr; -+ struct ast2600_espi_oob_dma_rx_desc *rxd_virt; -+ dma_addr_t rxd_addr; -+ void *tx_virt; -+ dma_addr_t tx_addr; -+ void *rx_virt; -+ dma_addr_t rx_addr; -+ } dma; ++ if (((wptr + 1) % OOB_DMA_DESC_NUM) == rptr) { ++ rc = -EBUSY; ++ goto free_n_out; ++ } + -+ bool rx_ready; -+ wait_queue_head_t wq; ++ tx_descs = (struct ast2600_espi_oob_dma_tx_desc *)oob->dma.txd_virt; ++ d = &tx_descs[wptr]; ++ d->cyc = hdr->cyc; ++ d->tag = hdr->tag; ++ d->len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ d->msg_type = OOB_DMA_DESC_CUSTOM; + -+ spinlock_t lock; -+ struct mutex tx_mtx; -+ struct mutex rx_mtx; ++ memcpy(oob->dma.tx_virt + (PAGE_SIZE * wptr), hdr + 1, ioc->pkt_len - sizeof(*hdr)); + -+ struct miscdevice mdev; -+}; ++ dma_wmb(); + -+struct ast2600_espi_flash { -+ struct { -+ uint32_t mode; -+ phys_addr_t taddr; -+ uint32_t size; -+ } safs; ++ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; ++ writel(wptr | ESPI_OOB_TX_DESC_WPTR_SEND_EN, espi->regs + ESPI_OOB_TX_DESC_WPTR); + -+ struct { -+ bool enable; -+ void *tx_virt; -+ dma_addr_t tx_addr; -+ void *rx_virt; -+ dma_addr_t rx_addr; -+ } dma; ++ rc = 0; + -+ bool rx_ready; -+ wait_queue_head_t wq; ++free_n_out: ++ vfree(pkt); + -+ spinlock_t lock; -+ struct mutex rx_mtx; -+ struct mutex tx_mtx; ++ return rc; ++} + -+ struct miscdevice mdev; -+}; ++static long ast2600_espi_oob_put_tx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u8 *pkt; ++ int i, rc; + -+struct ast2600_espi { -+ struct device *dev; -+ void __iomem *regs; -+ struct reset_control *rst; -+ struct clk *clk; -+ int irq; ++ espi = container_of(oob, struct aspeed_espi, oob); ++ ++ if (!mutex_trylock(&oob->tx_mtx)) ++ return -EAGAIN; ++ ++ if (oob->dma.enable) { ++ rc = ast2600_espi_oob_dma_put_tx(fp, oob, ioc); ++ goto unlock_mtx_n_out; ++ } ++ ++ reg = readl(espi->regs + ESPI_OOB_TX_CTRL); ++ if (reg & ESPI_OOB_TX_CTRL_TRIG_PEND) { ++ rc = -EBUSY; ++ goto unlock_mtx_n_out; ++ } ++ ++ if (ioc->pkt_len > ESPI_MAX_PKT_LEN) { ++ rc = -EINVAL; ++ goto unlock_mtx_n_out; ++ } ++ ++ pkt = vmalloc(ioc->pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; ++ } ++ ++ hdr = (struct espi_comm_hdr *)pkt; ++ ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } ++ ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) ++ writel(pkt[i], espi->regs + ESPI_OOB_TX_DATA); ++ ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ ++ reg = FIELD_PREP(ESPI_OOB_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_OOB_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_OOB_TX_CTRL_LEN, len) ++ | ESPI_OOB_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_OOB_TX_CTRL); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++unlock_mtx_n_out: ++ mutex_unlock(&oob->tx_mtx); ++ ++ return rc; ++} ++ ++static long ast2600_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ struct aspeed_espi_oob *oob; ++ struct aspeed_espi_ioc ioc; ++ ++ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); ++ ++ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) ++ return -EFAULT; ++ ++ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case ASPEED_ESPI_OOB_GET_RX: ++ return ast2600_espi_oob_get_rx(fp, oob, &ioc); ++ case ASPEED_ESPI_OOB_PUT_TX: ++ return ast2600_espi_oob_put_tx(fp, oob, &ioc); ++ }; ++ ++ return -EINVAL; ++} + -+ struct ast2600_espi_perif perif; -+ struct ast2600_espi_vw vw; -+ struct ast2600_espi_oob oob; -+ struct ast2600_espi_flash flash; ++static const struct file_operations ast2600_espi_oob_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2600_espi_oob_ioctl, +}; + -+/* peripheral channel (CH0) */ -+static int ast2600_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vma) ++static void ast2600_espi_oob_isr(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_perif_mmbi *mmbi; -+ struct ast2600_espi_perif *perif; -+ struct ast2600_espi *espi; -+ unsigned long vm_size; -+ pgprot_t prot; ++ struct aspeed_espi_oob *oob; ++ unsigned long flags; ++ u32 sts; + -+ mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, b2h_mdev); ++ oob = &espi->oob; + -+ perif = mmbi->perif; ++ sts = readl(espi->regs + ESPI_INT_STS); + -+ espi = container_of(perif, struct ast2600_espi, perif); ++ if (sts & ESPI_INT_STS_OOB_RX_CMPLT) { ++ writel(ESPI_INT_STS_OOB_RX_CMPLT, espi->regs + ESPI_INT_STS); + -+ vm_size = vma->vm_end - vma->vm_start; -+ prot = vma->vm_page_prot; ++ spin_lock_irqsave(&oob->lock, flags); ++ oob->rx_ready = true; ++ spin_unlock_irqrestore(&oob->lock, flags); + -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > (SZ_4K << perif->mmbi.inst_size)) -+ return -EINVAL; ++ wake_up_interruptible(&oob->wq); ++ } ++} + -+ prot = pgprot_noncached(prot); ++static void ast2600_espi_oob_reset(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_oob *oob; ++ struct ast2600_espi_oob_dma_tx_desc *tx_desc; ++ struct ast2600_espi_oob_dma_rx_desc *rx_desc; ++ dma_addr_t tx_addr, rx_addr; ++ u32 reg; ++ int i; + -+ if (remap_pfn_range(vma, vma->vm_start, -+ (mmbi->b2h_addr >> PAGE_SHIFT) + vma->vm_pgoff, -+ vm_size, prot)) -+ return -EAGAIN; ++ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); ++ writel(ESPI_INT_STS_OOB, espi->regs + ESPI_INT_STS); + -+ return 0; ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_OOB_TX_SW_RST ++ | ESPI_CTRL_OOB_RX_SW_RST ++ | ESPI_CTRL_OOB_TX_DMA_EN ++ | ESPI_CTRL_OOB_RX_DMA_EN ++ | ESPI_CTRL_OOB_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ udelay(1); ++ ++ reg |= (ESPI_CTRL_OOB_TX_SW_RST | ESPI_CTRL_OOB_RX_SW_RST); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ oob = &espi->oob; ++ ++ if (oob->dma.enable) { ++ tx_addr = oob->dma.tx_addr; ++ rx_addr = oob->dma.rx_addr; ++ ++ tx_desc = (struct ast2600_espi_oob_dma_tx_desc *)oob->dma.txd_virt; ++ rx_desc = (struct ast2600_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; ++ ++ for (i = 0; i < OOB_DMA_DESC_NUM; ++i) { ++ tx_desc[i].data_addr = tx_addr; ++ tx_addr += PAGE_SIZE; ++ ++ rx_desc[i].data_addr = rx_addr; ++ rx_desc[i].dirty = 0; ++ rx_addr += PAGE_SIZE; ++ } ++ ++ writel(oob->dma.txd_addr, espi->regs + ESPI_OOB_TX_DMA); ++ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_OOB_TX_DESC_RPTR); ++ writel(0x0, espi->regs + ESPI_OOB_TX_DESC_WPTR); ++ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_OOB_TX_DESC_NUM); ++ ++ writel(oob->dma.rxd_addr, espi->regs + ESPI_OOB_RX_DMA); ++ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_OOB_RX_DESC_RPTR); ++ writel(0x0, espi->regs + ESPI_OOB_RX_DESC_WPTR); ++ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_OOB_RX_DESC_NUM); ++ ++ reg = readl(espi->regs + ESPI_CTRL) ++ | ESPI_CTRL_OOB_TX_DMA_EN ++ | ESPI_CTRL_OOB_RX_DMA_EN; ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ /* activate RX DMA to make OOB_FREE */ ++ writel(ESPI_OOB_RX_DESC_WPTR_RECV_EN, espi->regs + ESPI_OOB_RX_DESC_WPTR); ++ } ++ ++ writel(ESPI_INT_EN_OOB_RX_CMPLT, espi->regs + ESPI_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_OOB_SW_RDY; ++ writel(reg, espi->regs + ESPI_CTRL); +} + -+static int ast2600_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) ++int ast2600_espi_oob_probe(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_perif_mmbi *mmbi; -+ struct ast2600_espi_perif *perif; -+ struct ast2600_espi *espi; -+ unsigned long vm_size; -+ pgprot_t prot; ++ struct aspeed_espi_oob *oob; ++ struct device *dev; ++ int rc; + -+ mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, h2b_mdev); ++ dev = espi->dev; + -+ perif = mmbi->perif; ++ oob = &espi->oob; ++ ++ init_waitqueue_head(&oob->wq); + -+ espi = container_of(perif, struct ast2600_espi, perif); ++ spin_lock_init(&oob->lock); + -+ vm_size = vma->vm_end - vma->vm_start; -+ prot = vma->vm_page_prot; ++ mutex_init(&oob->tx_mtx); ++ mutex_init(&oob->rx_mtx); + -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > (SZ_4K << perif->mmbi.inst_size)) -+ return -EINVAL; ++ oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); ++ if (oob->dma.enable) { ++ oob->dma.txd_virt = dmam_alloc_coherent(dev, ++ sizeof(struct ast2600_espi_oob_dma_tx_desc) * ++ OOB_DMA_DESC_NUM, ++ &oob->dma.txd_addr, GFP_KERNEL); ++ if (!oob->dma.txd_virt) { ++ dev_err(dev, "cannot allocate DMA TX descriptor\n"); ++ return -ENOMEM; ++ } ++ oob->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.tx_addr, GFP_KERNEL); ++ if (!oob->dma.tx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } + -+ prot = pgprot_noncached(prot); ++ oob->dma.rxd_virt = dmam_alloc_coherent(dev, ++ sizeof(struct ast2600_espi_oob_dma_rx_desc) * ++ OOB_DMA_DESC_NUM, ++ &oob->dma.rxd_addr, GFP_KERNEL); ++ if (!oob->dma.rxd_virt) { ++ dev_err(dev, "cannot allocate DMA RX descriptor\n"); ++ return -ENOMEM; ++ } + -+ if (remap_pfn_range(vma, vma->vm_start, -+ (mmbi->h2b_addr >> PAGE_SHIFT) + vma->vm_pgoff, -+ vm_size, prot)) -+ return -EAGAIN; ++ oob->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.rx_addr, GFP_KERNEL); ++ if (!oob->dma.rx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } ++ } ++ ++ oob->mdev.parent = dev; ++ oob->mdev.minor = MISC_DYNAMIC_MINOR; ++ oob->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-oob", DEVICE_NAME); ++ oob->mdev.fops = &ast2600_espi_oob_fops; ++ rc = misc_register(&oob->mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", oob->mdev.name); ++ return rc; ++ } ++ ++ ast2600_espi_oob_reset(espi); + + return 0; +} + -+static __poll_t ast2600_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) ++int ast2600_espi_oob_remove(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_perif_mmbi *mmbi; ++ struct aspeed_espi_oob *oob; ++ struct device *dev; ++ u32 reg; ++ ++ dev = espi->dev; ++ ++ oob = &espi->oob; ++ ++ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); ++ ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_OOB_TX_DMA_EN ++ | ESPI_CTRL_OOB_RX_DMA_EN ++ | ESPI_CTRL_OOB_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); + -+ mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, h2b_mdev); ++ if (oob->dma.enable) { ++ dmam_free_coherent(dev, ++ sizeof(struct ast2600_espi_oob_dma_tx_desc) * ++ OOB_DMA_DESC_NUM, ++ oob->dma.txd_virt, oob->dma.txd_addr); ++ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, ++ oob->dma.tx_virt, oob->dma.tx_addr); + -+ poll_wait(fp, &mmbi->wq, pt); ++ dmam_free_coherent(dev, ++ sizeof(struct ast2600_espi_oob_dma_rx_desc) * ++ OOB_DMA_DESC_NUM, ++ oob->dma.rxd_virt, oob->dma.rxd_addr); ++ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, ++ oob->dma.rx_virt, oob->dma.rx_addr); ++ } + -+ if (!mmbi->host_rwp_update) -+ return 0; ++ mutex_destroy(&oob->tx_mtx); ++ mutex_destroy(&oob->rx_mtx); + -+ mmbi->host_rwp_update = false; ++ misc_deregister(&oob->mdev); + -+ return EPOLLIN; ++ return 0; +} + -+static long ast2600_espi_perif_pc_get_rx(struct file *fp, -+ struct ast2600_espi_perif *perif, -+ struct aspeed_espi_ioc *ioc) ++/* flash channel (CH3) */ ++static long ast2600_espi_flash_get_rx(struct file *fp, ++ struct aspeed_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; ++ u32 pkt_len; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(perif, struct ast2600_espi, perif); ++ rc = 0; ++ ++ espi = container_of(flash, struct aspeed_espi, flash); + + if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&perif->pc_rx_mtx)) ++ if (!mutex_trylock(&flash->rx_mtx)) + return -EAGAIN; + -+ if (!perif->rx_ready) { ++ if (!flash->rx_ready) { + rc = -ENODATA; + goto unlock_mtx_n_out; + } + } else { -+ mutex_lock(&perif->pc_rx_mtx); ++ mutex_lock(&flash->rx_mtx); + -+ if (!perif->rx_ready) { -+ rc = wait_event_interruptible(perif->wq, perif->rx_ready); ++ if (!flash->rx_ready) { ++ rc = wait_event_interruptible(flash->wq, flash->rx_ready); + if (rc == -ERESTARTSYS) { + rc = -EINTR; + goto unlock_mtx_n_out; @@ -68994,10 +70311,10 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + * common header (i.e. cycle type, tag, and length) + * part is written to HW registers + */ -+ reg = readl(espi->regs + ESPI_PERIF_PC_RX_CTRL); -+ cyc = FIELD_GET(ESPI_PERIF_PC_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_PERIF_PC_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_PERIF_PC_RX_CTRL_LEN, reg); ++ reg = readl(espi->regs + ESPI_FLASH_RX_CTRL); ++ cyc = FIELD_GET(ESPI_FLASH_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_FLASH_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_FLASH_RX_CTRL_LEN, reg); + + /* + * calculate the length of the rest part of the @@ -69005,23 +70322,24 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + * user space. + */ + switch (cyc) { -+ case ESPI_PERIF_MSG: -+ pkt_len = sizeof(struct espi_perif_msg); -+ break; -+ case ESPI_PERIF_MSG_D: ++ case ESPI_FLASH_WRITE: + pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_perif_msg); ++ sizeof(struct espi_flash_rwe); + break; -+ case ESPI_PERIF_SUC_CMPLT_D_MIDDLE: -+ case ESPI_PERIF_SUC_CMPLT_D_FIRST: -+ case ESPI_PERIF_SUC_CMPLT_D_LAST: -+ case ESPI_PERIF_SUC_CMPLT_D_ONLY: ++ case ESPI_FLASH_READ: ++ case ESPI_FLASH_ERASE: ++ pkt_len = sizeof(struct espi_flash_rwe); ++ break; ++ case ESPI_FLASH_SUC_CMPLT_D_MIDDLE: ++ case ESPI_FLASH_SUC_CMPLT_D_FIRST: ++ case ESPI_FLASH_SUC_CMPLT_D_LAST: ++ case ESPI_FLASH_SUC_CMPLT_D_ONLY: + pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_perif_cmplt); ++ sizeof(struct espi_flash_cmplt); + break; -+ case ESPI_PERIF_SUC_CMPLT: -+ case ESPI_PERIF_UNSUC_CMPLT: -+ pkt_len = sizeof(struct espi_perif_cmplt); ++ case ESPI_FLASH_SUC_CMPLT: ++ case ESPI_FLASH_UNSUC_CMPLT: ++ pkt_len = sizeof(struct espi_flash_cmplt); + break; + default: + rc = -EFAULT; @@ -69045,11 +70363,11 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + hdr->len_h = len >> 8; + hdr->len_l = len & 0xff; + -+ if (perif->dma.enable) { -+ memcpy(hdr + 1, perif->dma.pc_rx_virt, pkt_len - sizeof(*hdr)); ++ if (flash->dma.enable) { ++ memcpy(hdr + 1, flash->dma.rx_virt, pkt_len - sizeof(*hdr)); + } else { + for (i = sizeof(*hdr); i < pkt_len; ++i) -+ reg = readl(espi->regs + ESPI_PERIF_PC_RX_DATA) & 0xff; ++ pkt[i] = readl(espi->regs + ESPI_FLASH_RX_DATA) & 0xff; + } + + if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { @@ -69057,12 +70375,12 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + goto free_n_out; + } + -+ spin_lock_irqsave(&perif->lock, flags); ++ spin_lock_irqsave(&flash->lock, flags); + -+ writel(ESPI_PERIF_PC_RX_CTRL_SERV_PEND, espi->regs + ESPI_PERIF_PC_RX_CTRL); -+ perif->rx_ready = 0; ++ writel(ESPI_FLASH_RX_CTRL_SERV_PEND, espi->regs + ESPI_FLASH_RX_CTRL); ++ flash->rx_ready = 0; + -+ spin_unlock_irqrestore(&perif->lock, flags); ++ spin_unlock_irqrestore(&flash->lock, flags); + + rc = 0; + @@ -69070,103 +70388,36 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&perif->pc_rx_mtx); -+ -+ return rc; -+} -+ -+static long ast2600_espi_perif_pc_put_tx(struct file *fp, -+ struct ast2600_espi_perif *perif, -+ struct aspeed_espi_ioc *ioc) -+{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint8_t *pkt; -+ int i, rc; -+ -+ espi = container_of(perif, struct ast2600_espi, perif); -+ -+ if (!mutex_trylock(&perif->pc_tx_mtx)) -+ return -EAGAIN; -+ -+ reg = readl(espi->regs + ESPI_PERIF_PC_TX_CTRL); -+ if (reg & ESPI_PERIF_PC_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_n_out; -+ } -+ -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_n_out; -+ } -+ -+ hdr = (struct espi_comm_hdr *)pkt; -+ -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } -+ -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ if (perif->dma.enable) { -+ memcpy(perif->dma.pc_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); -+ dma_wmb(); -+ } else { -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_PERIF_PC_TX_DATA); -+ } -+ -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -+ -+ reg = FIELD_PREP(ESPI_PERIF_PC_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_PERIF_PC_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_PERIF_PC_TX_CTRL_LEN, len) -+ | ESPI_PERIF_PC_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_PERIF_PC_TX_CTRL); -+ -+ rc = 0; -+ -+free_n_out: -+ vfree(pkt); -+ -+unlock_n_out: -+ mutex_unlock(&perif->pc_tx_mtx); ++ mutex_unlock(&flash->rx_mtx); + + return rc; +} + -+static long ast2600_espi_perif_np_put_tx(struct file *fp, -+ struct ast2600_espi_perif *perif, -+ struct aspeed_espi_ioc *ioc) ++static long ast2600_espi_flash_put_tx(struct file *fp, ++ struct aspeed_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(perif, struct ast2600_espi, perif); ++ espi = container_of(flash, struct aspeed_espi, flash); + -+ if (!mutex_trylock(&perif->np_tx_mtx)) ++ if (!mutex_trylock(&flash->tx_mtx)) + return -EAGAIN; + -+ reg = readl(espi->regs + ESPI_PERIF_NP_TX_CTRL); -+ if (reg & ESPI_PERIF_NP_TX_CTRL_TRIG_PEND) { ++ reg = readl(espi->regs + ESPI_FLASH_TX_CTRL); ++ if (reg & ESPI_FLASH_TX_CTRL_TRIG_PEND) { + rc = -EBUSY; -+ goto unlock_n_out; ++ goto unlock_mtx_n_out; + } + + pkt = vmalloc(ioc->pkt_len); + if (!pkt) { + rc = -ENOMEM; -+ goto unlock_n_out; ++ goto unlock_mtx_n_out; + } + + hdr = (struct espi_comm_hdr *)pkt; @@ -69180,41 +70431,41 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + * common header (i.e. cycle type, tag, and length) + * part is written to HW registers + */ -+ if (perif->dma.enable) { -+ memcpy(perif->dma.np_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ if (flash->dma.enable) { ++ memcpy(flash->dma.tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); + dma_wmb(); + } else { + for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_PERIF_NP_TX_DATA); ++ writel(pkt[i], espi->regs + ESPI_FLASH_TX_DATA); + } + + cyc = hdr->cyc; + tag = hdr->tag; + len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ reg = FIELD_PREP(ESPI_PERIF_NP_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_PERIF_NP_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_PERIF_NP_TX_CTRL_LEN, len) -+ | ESPI_PERIF_NP_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_PERIF_NP_TX_CTRL); ++ reg = FIELD_PREP(ESPI_FLASH_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_FLASH_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_FLASH_TX_CTRL_LEN, len) ++ | ESPI_FLASH_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_FLASH_TX_CTRL); + + rc = 0; + +free_n_out: + vfree(pkt); + -+unlock_n_out: -+ mutex_unlock(&perif->np_tx_mtx); ++unlock_mtx_n_out: ++ mutex_unlock(&flash->tx_mtx); + + return rc; +} + -+static long ast2600_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static long ast2600_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2600_espi_perif *perif; ++ struct aspeed_espi_flash *flash; + struct aspeed_espi_ioc ioc; + -+ perif = container_of(fp->private_data, struct ast2600_espi_perif, mdev); ++ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -69223,12 +70474,10 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + return -EINVAL; + + switch (cmd) { -+ case ASPEED_ESPI_PERIF_PC_GET_RX: -+ return ast2600_espi_perif_pc_get_rx(fp, perif, &ioc); -+ case ASPEED_ESPI_PERIF_PC_PUT_TX: -+ return ast2600_espi_perif_pc_put_tx(fp, perif, &ioc); -+ case ASPEED_ESPI_PERIF_NP_PUT_TX: -+ return ast2600_espi_perif_np_put_tx(fp, perif, &ioc); ++ case ASPEED_ESPI_FLASH_GET_RX: ++ return ast2600_espi_flash_get_rx(fp, flash, &ioc); ++ case ASPEED_ESPI_FLASH_PUT_TX: ++ return ast2600_espi_flash_put_tx(fp, flash, &ioc); + default: + break; + }; @@ -69236,663 +70485,621 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + return -EINVAL; +} + -+static int ast2600_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) -+{ -+ struct ast2600_espi_perif *perif; -+ unsigned long vm_size; -+ pgprot_t vm_prot; -+ -+ perif = container_of(fp->private_data, struct ast2600_espi_perif, mdev); -+ if (!perif->mcyc.enable) -+ return -EPERM; -+ -+ vm_size = vma->vm_end - vma->vm_start; -+ vm_prot = vma->vm_page_prot; -+ -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > perif->mcyc.size) -+ return -EINVAL; -+ -+ vm_prot = pgprot_noncached(vm_prot); -+ -+ if (remap_pfn_range(vma, vma->vm_start, -+ (perif->mcyc.taddr >> PAGE_SHIFT) + vma->vm_pgoff, -+ vm_size, vm_prot)) -+ return -EAGAIN; -+ -+ return 0; -+} -+ -+static const struct file_operations ast2600_espi_mmbi_b2h_fops = { -+ .owner = THIS_MODULE, -+ .mmap = ast2600_espi_mmbi_b2h_mmap, -+}; -+ -+static const struct file_operations ast2600_espi_mmbi_h2b_fops = { -+ .owner = THIS_MODULE, -+ .mmap = ast2600_espi_mmbi_h2b_mmap, -+ .poll = ast2600_espi_mmbi_h2b_poll, -+}; -+ -+static const struct file_operations ast2600_espi_perif_fops = { ++static const struct file_operations ast2600_espi_flash_fops = { + .owner = THIS_MODULE, -+ .mmap = ast2600_espi_perif_mmap, -+ .unlocked_ioctl = ast2600_espi_perif_ioctl, ++ .unlocked_ioctl = ast2600_espi_flash_ioctl, +}; + -+static irqreturn_t ast2600_espi_perif_mmbi_isr(int irq, void *arg) -+{ -+ struct ast2600_espi_perif_mmbi *mmbi; -+ struct ast2600_espi_perif *perif; -+ struct ast2600_espi *espi; -+ uint32_t sts, tmp; -+ uint32_t *p; -+ int i; -+ -+ espi = (struct ast2600_espi *)arg; -+ -+ perif = &espi->perif; -+ -+ sts = readl(espi->regs + ESPI_MMBI_INT_STS); -+ if (!sts) -+ return IRQ_NONE; -+ -+ for (i = 0, tmp = sts; i < PERIF_MMBI_INST_NUM; ++i, tmp >>= 2) { -+ if (!(tmp & 0x3)) -+ continue; -+ -+ mmbi = &perif->mmbi.inst[i]; -+ -+ p = (uint32_t *)mmbi->h2b_virt; -+ p[0] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i)); -+ p[1] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i) + 4); -+ -+ mmbi->host_rwp_update = true; -+ -+ wake_up_interruptible(&mmbi->wq); -+ } -+ -+ writel(sts, espi->regs + ESPI_MMBI_INT_STS); -+ -+ return IRQ_HANDLED; -+} -+ -+static void ast2600_espi_perif_isr(struct ast2600_espi *espi) ++static void ast2600_espi_flash_isr(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_perif *perif; ++ struct aspeed_espi_flash *flash; + unsigned long flags; -+ uint32_t sts; ++ u32 sts; + -+ perif = &espi->perif; ++ flash = &espi->flash; + + sts = readl(espi->regs + ESPI_INT_STS); + -+ if (sts & ESPI_INT_STS_PERIF_PC_RX_CMPLT) { -+ writel(ESPI_INT_STS_PERIF_PC_RX_CMPLT, espi->regs + ESPI_INT_STS); ++ if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) { ++ writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); + -+ spin_lock_irqsave(&perif->lock, flags); -+ perif->rx_ready = true; -+ spin_unlock_irqrestore(&perif->lock, flags); ++ spin_lock_irqsave(&flash->lock, flags); ++ flash->rx_ready = true; ++ spin_unlock_irqrestore(&flash->lock, flags); + -+ wake_up_interruptible(&perif->wq); ++ wake_up_interruptible(&flash->wq); + } +} + -+static void ast2600_espi_perif_sw_reset(struct ast2600_espi *espi) -+{ -+ struct device *dev; -+ uint32_t reg; -+ -+ dev = espi->dev; -+ -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_PERIF_NP_TX_SW_RST -+ | ESPI_CTRL_PERIF_NP_RX_SW_RST -+ | ESPI_CTRL_PERIF_PC_TX_SW_RST -+ | ESPI_CTRL_PERIF_PC_RX_SW_RST -+ | ESPI_CTRL_PERIF_NP_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_RX_DMA_EN -+ | ESPI_CTRL_PERIF_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); -+ -+ udelay(1); -+ -+ reg |= (ESPI_CTRL_PERIF_NP_TX_SW_RST -+ | ESPI_CTRL_PERIF_NP_RX_SW_RST -+ | ESPI_CTRL_PERIF_PC_TX_SW_RST -+ | ESPI_CTRL_PERIF_PC_RX_SW_RST); -+ writel(reg, espi->regs + ESPI_CTRL); -+} -+ -+static void ast2600_espi_perif_reset(struct ast2600_espi *espi) ++static void ast2600_espi_flash_reset(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_perif *perif; -+ struct device *dev; -+ uint32_t reg, mask; -+ -+ dev = espi->dev; -+ -+ perif = &espi->perif; -+ -+ writel(ESPI_INT_EN_PERIF, espi->regs + ESPI_INT_EN_CLR); -+ writel(ESPI_INT_STS_PERIF, espi->regs + ESPI_INT_STS); ++ struct aspeed_espi_flash *flash; ++ u32 reg; + -+ writel(0x0, espi->regs + ESPI_MMBI_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_MMBI_INT_STS); ++ flash = &espi->flash; + -+ reg = readl(espi->regs + ESPI_CTRL2); -+ reg &= ~(ESPI_CTRL2_MCYC_RD_DIS_WDT | ESPI_CTRL2_MCYC_WR_DIS_WDT); -+ writel(reg, espi->regs + ESPI_CTRL2); ++ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); ++ writel(ESPI_INT_STS_FLASH, espi->regs + ESPI_INT_STS); + + reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_PERIF_NP_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_RX_DMA_EN -+ | ESPI_CTRL_PERIF_SW_RDY); ++ reg &= ~(ESPI_CTRL_FLASH_TX_SW_RST ++ | ESPI_CTRL_FLASH_RX_SW_RST ++ | ESPI_CTRL_FLASH_TX_DMA_EN ++ | ESPI_CTRL_FLASH_RX_DMA_EN ++ | ESPI_CTRL_FLASH_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + -+ if (perif->mmbi.enable) { -+ reg = readl(espi->regs + ESPI_MMBI_CTRL); -+ reg &= ~(ESPI_MMBI_CTRL_EN); -+ writel(reg, espi->regs + ESPI_MMBI_CTRL); -+ -+ mask = ~(perif->mmbi.size - 1); -+ writel(mask, espi->regs + ESPI_PERIF_MMBI_MASK); -+ writel(perif->mmbi.saddr, espi->regs + ESPI_PERIF_MMBI_SADDR); -+ writel(perif->mmbi.taddr, espi->regs + ESPI_PERIF_MMBI_TADDR); -+ -+ writel(0xffffffff, espi->regs + ESPI_MMBI_INT_EN); -+ -+ reg = FIELD_PREP(ESPI_MMBI_CTRL_INST_SZ, perif->mmbi.inst_size) -+ | FIELD_PREP(ESPI_MMBI_CTRL_TOTAL_SZ, perif->mmbi.inst_size) -+ | ESPI_MMBI_CTRL_EN; -+ writel(reg, espi->regs + ESPI_MMBI_CTRL); -+ -+ reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_MMBI_RD_DIS | ESPI_CTRL2_MMBI_WR_DIS); -+ writel(reg, espi->regs + ESPI_CTRL2); -+ } -+ -+ if (perif->mcyc.enable) { -+ mask = ~(perif->mcyc.size - 1); -+ writel(mask, espi->regs + ESPI_PERIF_MCYC_MASK); -+ writel(perif->mcyc.saddr, espi->regs + ESPI_PERIF_MCYC_SADDR); -+ writel(perif->mcyc.taddr, espi->regs + ESPI_PERIF_MCYC_TADDR); -+ -+ reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_MCYC_RD_DIS | ESPI_CTRL2_MCYC_WR_DIS); -+ writel(reg, espi->regs + ESPI_CTRL2); -+ } -+ -+ if (perif->dma.enable) { -+ writel(perif->dma.np_tx_addr, espi->regs + ESPI_PERIF_NP_TX_DMA); -+ writel(perif->dma.pc_tx_addr, espi->regs + ESPI_PERIF_PC_TX_DMA); -+ writel(perif->dma.pc_rx_addr, espi->regs + ESPI_PERIF_PC_RX_DMA); -+ -+ reg = readl(espi->regs + ESPI_CTRL) -+ | ESPI_CTRL_PERIF_NP_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CTRL); -+ } -+ -+ writel(ESPI_INT_EN_PERIF_PC_RX_CMPLT, espi->regs + ESPI_INT_EN); ++ udelay(1); + -+ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_PERIF_SW_RDY; ++ reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); + writel(reg, espi->regs + ESPI_CTRL); -+} -+ -+static int ast2600_espi_perif_probe(struct ast2600_espi *espi) -+{ -+ struct ast2600_espi_perif_mmbi *mmbi; -+ struct ast2600_espi_perif *perif; -+ struct platform_device *pdev; -+ struct device *dev; -+ int i, rc; -+ -+ dev = espi->dev; -+ -+ perif = &espi->perif; -+ -+ init_waitqueue_head(&perif->wq); -+ -+ spin_lock_init(&perif->lock); -+ -+ mutex_init(&perif->np_tx_mtx); -+ mutex_init(&perif->pc_tx_mtx); -+ mutex_init(&perif->pc_rx_mtx); -+ -+ perif->mmbi.enable = of_property_read_bool(dev->of_node, "perif-mmbi-enable"); -+ if (perif->mmbi.enable) { -+ pdev = container_of(dev, struct platform_device, dev); -+ -+ perif->mmbi.irq = platform_get_irq(pdev, 1); -+ if (perif->mmbi.irq < 0) { -+ dev_err(dev, "cannot get MMBI IRQ number\n"); -+ return -ENODEV; -+ } -+ -+ rc = of_property_read_u32(dev->of_node, "perif-mmbi-src-addr", &perif->mmbi.saddr); -+ if (rc || !IS_ALIGNED(perif->mmbi.saddr, PERIF_MMBI_ALIGN)) { -+ dev_err(dev, "cannot get 64KB-aligned MMBI host address\n"); -+ return -ENODEV; -+ } -+ -+ rc = of_property_read_u32(dev->of_node, "perif-mmbi-instance-size", &perif->mmbi.inst_size); -+ if (rc || perif->mmbi.inst_size >= MMBI_INST_SIZE_TYPES) { -+ dev_err(dev, "cannot get valid MMBI instance size\n"); -+ return -EINVAL; -+ } -+ -+ perif->mmbi.size = (SZ_8K << perif->mmbi.inst_size) * PERIF_MMBI_INST_NUM; -+ perif->mmbi.virt = dmam_alloc_coherent(dev, perif->mmbi.size, -+ &perif->mmbi.taddr, GFP_KERNEL); -+ if (!perif->mmbi.virt) { -+ dev_err(dev, "cannot allocate MMBI\n"); -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < PERIF_MMBI_INST_NUM; ++i) { -+ mmbi = &perif->mmbi.inst[i]; -+ -+ init_waitqueue_head(&mmbi->wq); -+ -+ mmbi->perif = perif; -+ mmbi->host_rwp_update = false; -+ -+ mmbi->b2h_virt = perif->mmbi.virt + ((SZ_4K << perif->mmbi.inst_size) * i); -+ mmbi->b2h_addr = perif->mmbi.taddr + ((SZ_4K << perif->mmbi.inst_size) * i); -+ mmbi->b2h_mdev.parent = dev; -+ mmbi->b2h_mdev.minor = MISC_DYNAMIC_MINOR; -+ mmbi->b2h_mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-mmbi-b2h%d", DEVICE_NAME, i); -+ mmbi->b2h_mdev.fops = &ast2600_espi_mmbi_b2h_fops; -+ rc = misc_register(&mmbi->b2h_mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", mmbi->b2h_mdev.name); -+ return rc; -+ } -+ -+ mmbi->h2b_virt = perif->mmbi.virt + ((SZ_4K << perif->mmbi.inst_size) * (i + PERIF_MMBI_INST_NUM)); -+ mmbi->h2b_addr = perif->mmbi.taddr + ((SZ_4K << perif->mmbi.inst_size) * (i + PERIF_MMBI_INST_NUM)); -+ mmbi->h2b_mdev.parent = dev; -+ mmbi->h2b_mdev.minor = MISC_DYNAMIC_MINOR; -+ mmbi->h2b_mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-mmbi-h2b%d", DEVICE_NAME, i); -+ mmbi->h2b_mdev.fops = &ast2600_espi_mmbi_h2b_fops; -+ rc = misc_register(&mmbi->h2b_mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", mmbi->h2b_mdev.name); -+ return rc; -+ } -+ } -+ } -+ -+ perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); -+ if (perif->mcyc.enable) { -+ if (perif->mmbi.enable) { -+ dev_err(dev, "cannot enable memory cycle, occupied by MMBI\n"); -+ return -EPERM; -+ } -+ -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", &perif->mcyc.saddr); -+ if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { -+ dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); -+ return -ENODEV; -+ } -+ -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", &perif->mcyc.size); -+ if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { -+ dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); -+ return -EINVAL; -+ } -+ -+ perif->mcyc.virt = dmam_alloc_coherent(dev, perif->mcyc.size, -+ &perif->mcyc.taddr, GFP_KERNEL); -+ if (!perif->mcyc.virt) { -+ dev_err(dev, "cannot allocate memory cycle\n"); -+ return -ENOMEM; -+ } -+ } -+ -+ perif->dma.enable = of_property_read_bool(dev->of_node, "perif-dma-mode"); -+ if (perif->dma.enable) { -+ perif->dma.pc_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, -+ &perif->dma.pc_tx_addr, GFP_KERNEL); -+ if (!perif->dma.pc_tx_virt) { -+ dev_err(dev, "cannot allocate posted TX DMA buffer\n"); -+ return -ENOMEM; -+ } -+ -+ perif->dma.pc_rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, -+ &perif->dma.pc_rx_addr, GFP_KERNEL); -+ if (!perif->dma.pc_rx_virt) { -+ dev_err(dev, "cannot allocate posted RX DMA buffer\n"); -+ return -ENOMEM; -+ } -+ -+ perif->dma.np_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, -+ &perif->dma.np_tx_addr, GFP_KERNEL); -+ if (!perif->dma.np_tx_virt) { -+ dev_err(dev, "cannot allocate non-posted TX DMA buffer\n"); -+ return -ENOMEM; -+ } -+ } -+ -+ perif->mdev.parent = dev; -+ perif->mdev.minor = MISC_DYNAMIC_MINOR; -+ perif->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-peripheral", DEVICE_NAME); -+ perif->mdev.fops = &ast2600_espi_perif_fops; -+ rc = misc_register(&perif->mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", perif->mdev.name); -+ return rc; ++ ++ reg = readl(espi->regs + ESPI_CTRL) & ~ESPI_CTRL_FLASH_EDAF_MODE; ++ reg |= FIELD_PREP(ESPI_CTRL_FLASH_EDAF_MODE, flash->edaf.mode); ++ writel(reg, espi->regs + ESPI_CTRL); ++ ++ if (flash->edaf.mode == EDAF_MODE_MIX) { ++ reg = FIELD_PREP(ESPI_FLASH_EDAF_TADDR_BASE, flash->edaf.taddr >> 24) ++ | FIELD_PREP(ESPI_FLASH_EDAF_TADDR_MASK, (~(flash->edaf.size - 1)) >> 24); ++ writel(reg, espi->regs + ESPI_FLASH_EDAF_TADDR); + } + -+ ast2600_espi_perif_reset(espi); ++ if (flash->dma.enable) { ++ writel(flash->dma.tx_addr, espi->regs + ESPI_FLASH_TX_DMA); ++ writel(flash->dma.rx_addr, espi->regs + ESPI_FLASH_RX_DMA); + -+ if (perif->mmbi.enable) { -+ rc = devm_request_irq(dev, espi->perif.mmbi.irq, -+ ast2600_espi_perif_mmbi_isr, 0, dev_name(dev), espi); -+ if (rc) { -+ dev_err(dev, "cannot request MMBI IRQ\n"); -+ return rc; -+ } ++ reg = readl(espi->regs + ESPI_CTRL) ++ | ESPI_CTRL_FLASH_TX_DMA_EN ++ | ESPI_CTRL_FLASH_RX_DMA_EN; ++ writel(reg, espi->regs + ESPI_CTRL); + } + -+ return 0; ++ writel(ESPI_INT_EN_FLASH_RX_CMPLT, espi->regs + ESPI_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SW_RDY; ++ writel(reg, espi->regs + ESPI_CTRL); +} + -+static int ast2600_espi_perif_remove(struct ast2600_espi *espi) ++int ast2600_espi_flash_probe(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_perif_mmbi *mmbi; -+ struct ast2600_espi_perif *perif; ++ struct aspeed_espi_flash *flash; + struct device *dev; -+ uint32_t reg; -+ int i; ++ int rc; + + dev = espi->dev; + -+ perif = &espi->perif; ++ flash = &espi->flash; + -+ writel(ESPI_INT_EN_PERIF, espi->regs + ESPI_INT_EN_CLR); ++ init_waitqueue_head(&flash->wq); + -+ reg = readl(espi->regs + ESPI_CTRL2); -+ reg |= (ESPI_CTRL2_MCYC_RD_DIS | ESPI_CTRL2_MCYC_WR_DIS); -+ writel(reg, espi->regs + ESPI_CTRL2); ++ spin_lock_init(&flash->lock); + -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_PERIF_NP_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_TX_DMA_EN -+ | ESPI_CTRL_PERIF_PC_RX_DMA_EN -+ | ESPI_CTRL_PERIF_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); ++ mutex_init(&flash->tx_mtx); ++ mutex_init(&flash->rx_mtx); + -+ if (perif->mmbi.enable) { -+ reg = readl(espi->regs + ESPI_MMBI_CTRL); -+ reg &= ~ESPI_MMBI_CTRL_EN; -+ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ flash->edaf.mode = EDAF_MODE_HW; + -+ for (i = 0; i < PERIF_MMBI_INST_NUM; ++i) { -+ mmbi = &perif->mmbi.inst[i]; -+ misc_deregister(&mmbi->b2h_mdev); -+ misc_deregister(&mmbi->h2b_mdev); ++ of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->edaf.mode); ++ if (flash->edaf.mode == EDAF_MODE_MIX) { ++ rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", (u32 *)&flash->edaf.taddr); ++ if (rc || !IS_ALIGNED(flash->edaf.taddr, FLASH_EDAF_ALIGN)) { ++ dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); ++ return -ENODEV; + } + -+ dmam_free_coherent(dev, perif->mmbi.size, perif->mmbi.virt, -+ perif->mmbi.taddr); ++ rc = of_property_read_u32(dev->of_node, "flash-safs-size", (u32 *)&flash->edaf.size); ++ if (rc || !IS_ALIGNED(flash->edaf.size, FLASH_EDAF_ALIGN)) { ++ dev_err(dev, "cannot get 16MB-aligned SAFS size\n"); ++ return -ENODEV; ++ } + } + -+ if (perif->mcyc.enable) -+ dmam_free_coherent(dev, perif->mcyc.size, perif->mcyc.virt, -+ perif->mcyc.taddr); ++ flash->dma.enable = of_property_read_bool(dev->of_node, "flash-dma-mode"); ++ if (flash->dma.enable) { ++ flash->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.tx_addr, GFP_KERNEL); ++ if (!flash->dma.tx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } + -+ if (perif->dma.enable) { -+ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.np_tx_virt, -+ perif->dma.np_tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_tx_virt, -+ perif->dma.pc_tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_rx_virt, -+ perif->dma.pc_rx_addr); ++ flash->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.rx_addr, GFP_KERNEL); ++ if (!flash->dma.rx_virt) { ++ dev_err(dev, "cannot allocate DMA RX buffer\n"); ++ return -ENOMEM; ++ } + } + -+ mutex_destroy(&perif->np_tx_mtx); -+ mutex_destroy(&perif->pc_tx_mtx); -+ mutex_destroy(&perif->pc_rx_mtx); ++ flash->mdev.parent = dev; ++ flash->mdev.minor = MISC_DYNAMIC_MINOR; ++ flash->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-flash", DEVICE_NAME); ++ flash->mdev.fops = &ast2600_espi_flash_fops; ++ rc = misc_register(&flash->mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", flash->mdev.name); ++ return rc; ++ } + -+ misc_deregister(&perif->mdev); ++ ast2600_espi_flash_reset(espi); + + return 0; +} + -+/* virtual wire channel (CH1) */ -+static long ast2600_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++int ast2600_espi_flash_remove(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_vw *vw; -+ struct ast2600_espi *espi; -+ uint32_t gpio, hw_mode; ++ struct aspeed_espi_flash *flash; ++ struct device *dev; ++ u32 reg; + -+ vw = container_of(fp->private_data, struct ast2600_espi_vw, mdev); -+ espi = container_of(vw, struct ast2600_espi, vw); -+ gpio = vw->gpio.val; -+ hw_mode = vw->gpio.hw_mode; ++ dev = espi->dev; + -+ if (hw_mode) { -+ dev_err(espi->dev, "HW mode: vGPIO reflect on physical GPIO. Get state from GPIO driver.\n"); -+ return -EFAULT; -+ } ++ flash = &espi->flash; + -+ switch (cmd) { -+ case ASPEED_ESPI_VW_GET_GPIO_VAL: -+ if (put_user(gpio, (uint32_t __user *)arg)) { -+ dev_err(espi->dev, "failed to get vGPIO value\n"); -+ return -EFAULT; -+ } ++ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); + -+ dev_info(espi->dev, "Get vGPIO value: 0x%x\n", gpio); -+ break; ++ reg = readl(espi->regs + ESPI_CTRL); ++ reg &= ~(ESPI_CTRL_FLASH_TX_DMA_EN ++ | ESPI_CTRL_FLASH_RX_DMA_EN ++ | ESPI_CTRL_FLASH_SW_RDY); ++ writel(reg, espi->regs + ESPI_CTRL); + -+ case ASPEED_ESPI_VW_PUT_GPIO_VAL: -+ if (get_user(gpio, (uint32_t __user *)arg)) { -+ dev_err(espi->dev, "failed to put vGPIO value\n"); -+ return -EFAULT; -+ } ++ if (flash->dma.enable) { ++ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.rx_addr); ++ } + -+ dev_info(espi->dev, "Put vGPIO value: 0x%x\n", gpio); -+ writel(gpio, espi->regs + ESPI_VW_GPIO_VAL); -+ break; ++ mutex_destroy(&flash->tx_mtx); ++ mutex_destroy(&flash->rx_mtx); + -+ default: -+ return -EINVAL; -+ }; ++ misc_deregister(&flash->mdev); + + return 0; +} + -+static const struct file_operations ast2600_espi_vw_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2600_espi_vw_ioctl, -+}; -+ -+static void ast2600_espi_vw_isr(struct ast2600_espi *espi) ++/* global control */ ++irqreturn_t ast2600_espi_isr(int irq, void *arg) +{ -+ struct ast2600_espi_vw *vw; -+ uint32_t sts; ++ struct aspeed_espi *espi; ++ u32 sts; + -+ vw = &espi->vw; ++ espi = (struct aspeed_espi *)arg; + + sts = readl(espi->regs + ESPI_INT_STS); ++ if (!sts) ++ return IRQ_NONE; + -+ if (sts & ESPI_INT_STS_VW_GPIO) { -+ vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); -+ writel(ESPI_INT_STS_VW_GPIO, espi->regs + ESPI_INT_STS); -+ } else if (sts & ESPI_INT_STS_VW_SYSEVT) { -+ /* Handle system event */ -+ writel(ESPI_INT_STS_VW_SYSEVT, espi->regs + ESPI_INT_STS); -+ } else if (sts & (ESPI_INT_STS_VW_SYSEVT1)) { -+ /* Handle system event1 */ -+ writel(ESPI_INT_STS_VW_SYSEVT1, espi->regs + ESPI_INT_STS); -+ } -+} -+ -+static void ast2600_espi_vw_reset(struct ast2600_espi *espi) -+{ -+ uint32_t reg; -+ struct ast2600_espi_vw *vw = &espi->vw; -+ -+ writel(ESPI_INT_EN_VW, espi->regs + ESPI_INT_EN_CLR); -+ writel(ESPI_INT_STS_VW, espi->regs + ESPI_INT_STS); -+ -+ writel(vw->gpio.dir, espi->regs + ESPI_VW_GPIO_DIR); ++ if (sts & ESPI_INT_STS_PERIF) ++ ast2600_espi_perif_isr(espi); + -+ vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ if (sts & ESPI_INT_STS_VW) ++ ast2600_espi_vw_isr(espi); + -+ reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_VW_TX_SORT); -+ writel(reg, espi->regs + ESPI_CTRL2); ++ if (sts & ESPI_INT_STS_OOB) ++ ast2600_espi_oob_isr(espi); + -+ writel(ESPI_INT_EN_VW_GPIO, espi->regs + ESPI_INT_EN); ++ if (sts & ESPI_INT_STS_FLASH) ++ ast2600_espi_flash_isr(espi); + -+ reg = readl(espi->regs + ESPI_CTRL) -+ | ((vw->gpio.hw_mode) ? 0 : ESPI_CTRL_VW_GPIO_SW) -+ | ESPI_CTRL_VW_SW_RDY; -+ writel(reg, espi->regs + ESPI_CTRL); ++ if (sts & ESPI_INT_STS_RST_DEASSERT) { ++ /* this will clear all interrupt enable and status */ ++ reset_control_assert(espi->rst); ++ reset_control_deassert(espi->rst); + -+ writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_T0); -+ writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_T1); ++ ast2600_espi_perif_sw_reset(espi); ++ ast2600_espi_perif_reset(espi); ++ ast2600_espi_vw_reset(espi); ++ ast2600_espi_oob_reset(espi); ++ ast2600_espi_flash_reset(espi); + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg |= ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++ /* re-enable eSPI_RESET# interrupt */ ++ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); ++ } + -+ writel(0xffffffff, espi->regs + ESPI_VW_SYSEVT_INT_EN); -+ writel(0x1, espi->regs + ESPI_VW_SYSEVT1_INT_EN); -+ writel(0x1, espi->regs + ESPI_VW_SYSEVT1_INT_T0); ++ return IRQ_HANDLED; +} + -+static int ast2600_espi_vw_probe(struct ast2600_espi *espi) ++void ast2600_espi_pre_init(struct aspeed_espi *espi) +{ -+ int rc; -+ struct device *dev = espi->dev; -+ struct ast2600_espi_vw *vw = &espi->vw; -+ -+ vw->gpio.hw_mode = of_property_read_bool(dev->of_node, "vw-gpio-hw-mode"); -+ of_property_read_u32(dev->of_node, "vw-gpio-direction", &vw->gpio.dir); -+ -+ vw->mdev.parent = dev; -+ vw->mdev.minor = MISC_DYNAMIC_MINOR; -+ vw->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-vw", DEVICE_NAME); -+ vw->mdev.fops = &ast2600_espi_vw_fops; -+ rc = misc_register(&vw->mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", vw->mdev.name); -+ return rc; -+ } -+ -+ ast2600_espi_vw_reset(espi); -+ -+ return 0; ++ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); +} + -+static int ast2600_espi_vw_remove(struct ast2600_espi *espi) ++void ast2600_espi_post_init(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_vw *vw; -+ -+ vw = &espi->vw; -+ -+ writel(ESPI_INT_EN_VW, espi->regs + ESPI_INT_EN_CLR); -+ -+ misc_deregister(&vw->mdev); -+ -+ return 0; ++ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); +} + -+/* out-of-band channel (CH2) */ -+static long ast2600_espi_oob_dma_get_rx(struct file *fp, -+ struct ast2600_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++void ast2600_espi_deinit(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_oob_dma_rx_desc *d; -+ struct ast2600_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint32_t wptr, pkt_len; -+ unsigned long flags; -+ uint8_t *pkt; -+ int rc; ++ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); ++} +diff --git a/drivers/soc/aspeed/espi/ast2600-espi.h b/drivers/soc/aspeed/espi/ast2600-espi.h +--- a/drivers/soc/aspeed/espi/ast2600-espi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2600-espi.h 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,306 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Register definitions for Aspeed AST2600 eSPI controller ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#ifndef _AST2600_ESPI_H_ ++#define _AST2600_ESPI_H_ ++ ++#include ++#include + -+ espi = container_of(oob, struct ast2600_espi, oob); ++#include "aspeed-espi.h" + -+ wptr = FIELD_PREP(ESPI_OOB_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_OOB_RX_DESC_WPTR)); ++/* registers */ ++#define ESPI_CTRL 0x000 ++#define ESPI_CTRL_FLASH_TX_SW_RST BIT(31) ++#define ESPI_CTRL_FLASH_RX_SW_RST BIT(30) ++#define ESPI_CTRL_OOB_TX_SW_RST BIT(29) ++#define ESPI_CTRL_OOB_RX_SW_RST BIT(28) ++#define ESPI_CTRL_PERIF_NP_TX_SW_RST BIT(27) ++#define ESPI_CTRL_PERIF_NP_RX_SW_RST BIT(26) ++#define ESPI_CTRL_PERIF_PC_TX_SW_RST BIT(25) ++#define ESPI_CTRL_PERIF_PC_RX_SW_RST BIT(24) ++#define ESPI_CTRL_FLASH_TX_DMA_EN BIT(23) ++#define ESPI_CTRL_FLASH_RX_DMA_EN BIT(22) ++#define ESPI_CTRL_OOB_TX_DMA_EN BIT(21) ++#define ESPI_CTRL_OOB_RX_DMA_EN BIT(20) ++#define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) ++#define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) ++#define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) ++#define ESPI_CTRL_FLASH_EDAF_MODE GENMASK(11, 10) ++#define ESPI_CTRL_VW_GPIO_SW BIT(9) ++#define ESPI_CTRL_FLASH_SW_RDY BIT(7) ++#define ESPI_CTRL_OOB_SW_RDY BIT(4) ++#define ESPI_CTRL_VW_SW_RDY BIT(3) ++#define ESPI_CTRL_PERIF_SW_RDY BIT(1) ++#define ESPI_STS 0x004 ++#define ESPI_INT_STS 0x008 ++#define ESPI_INT_STS_RST_DEASSERT BIT(31) ++#define ESPI_INT_STS_OOB_RX_TMOUT BIT(23) ++#define ESPI_INT_STS_VW_SYSEVT1 BIT(22) ++#define ESPI_INT_STS_FLASH_TX_ERR BIT(21) ++#define ESPI_INT_STS_OOB_TX_ERR BIT(20) ++#define ESPI_INT_STS_FLASH_TX_ABT BIT(19) ++#define ESPI_INT_STS_OOB_TX_ABT BIT(18) ++#define ESPI_INT_STS_PERIF_NP_TX_ABT BIT(17) ++#define ESPI_INT_STS_PERIF_PC_TX_ABT BIT(16) ++#define ESPI_INT_STS_FLASH_RX_ABT BIT(15) ++#define ESPI_INT_STS_OOB_RX_ABT BIT(14) ++#define ESPI_INT_STS_PERIF_NP_RX_ABT BIT(13) ++#define ESPI_INT_STS_PERIF_PC_RX_ABT BIT(12) ++#define ESPI_INT_STS_PERIF_NP_TX_ERR BIT(11) ++#define ESPI_INT_STS_PERIF_PC_TX_ERR BIT(10) ++#define ESPI_INT_STS_VW_GPIO BIT(9) ++#define ESPI_INT_STS_VW_SYSEVT BIT(8) ++#define ESPI_INT_STS_FLASH_TX_CMPLT BIT(7) ++#define ESPI_INT_STS_FLASH_RX_CMPLT BIT(6) ++#define ESPI_INT_STS_OOB_TX_CMPLT BIT(5) ++#define ESPI_INT_STS_OOB_RX_CMPLT BIT(4) ++#define ESPI_INT_STS_PERIF_NP_TX_CMPLT BIT(3) ++#define ESPI_INT_STS_PERIF_PC_TX_CMPLT BIT(1) ++#define ESPI_INT_STS_PERIF_PC_RX_CMPLT BIT(0) ++#define ESPI_INT_EN 0x00c ++#define ESPI_INT_EN_RST_DEASSERT BIT(31) ++#define ESPI_INT_EN_OOB_RX_TMOUT BIT(23) ++#define ESPI_INT_EN_VW_SYSEVT1 BIT(22) ++#define ESPI_INT_EN_FLASH_TX_ERR BIT(21) ++#define ESPI_INT_EN_OOB_TX_ERR BIT(20) ++#define ESPI_INT_EN_FLASH_TX_ABT BIT(19) ++#define ESPI_INT_EN_OOB_TX_ABT BIT(18) ++#define ESPI_INT_EN_PERIF_NP_TX_ABT BIT(17) ++#define ESPI_INT_EN_PERIF_PC_TX_ABT BIT(16) ++#define ESPI_INT_EN_FLASH_RX_ABT BIT(15) ++#define ESPI_INT_EN_OOB_RX_ABT BIT(14) ++#define ESPI_INT_EN_PERIF_NP_RX_ABT BIT(13) ++#define ESPI_INT_EN_PERIF_PC_RX_ABT BIT(12) ++#define ESPI_INT_EN_PERIF_NP_TX_ERR BIT(11) ++#define ESPI_INT_EN_PERIF_PC_TX_ERR BIT(10) ++#define ESPI_INT_EN_VW_GPIO BIT(9) ++#define ESPI_INT_EN_VW_SYSEVT BIT(8) ++#define ESPI_INT_EN_FLASH_TX_CMPLT BIT(7) ++#define ESPI_INT_EN_FLASH_RX_CMPLT BIT(6) ++#define ESPI_INT_EN_OOB_TX_CMPLT BIT(5) ++#define ESPI_INT_EN_OOB_RX_CMPLT BIT(4) ++#define ESPI_INT_EN_PERIF_NP_TX_CMPLT BIT(3) ++#define ESPI_INT_EN_PERIF_PC_TX_CMPLT BIT(1) ++#define ESPI_INT_EN_PERIF_PC_RX_CMPLT BIT(0) ++#define ESPI_PERIF_PC_RX_DMA 0x010 ++#define ESPI_PERIF_PC_RX_CTRL 0x014 ++#define ESPI_PERIF_PC_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_PERIF_PC_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_PERIF_PC_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_PERIF_PC_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_PERIF_PC_RX_DATA 0x018 ++#define ESPI_PERIF_PC_TX_DMA 0x020 ++#define ESPI_PERIF_PC_TX_CTRL 0x024 ++#define ESPI_PERIF_PC_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_PERIF_PC_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_PERIF_PC_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_PERIF_PC_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_PERIF_PC_TX_DATA 0x028 ++#define ESPI_PERIF_NP_TX_DMA 0x030 ++#define ESPI_PERIF_NP_TX_CTRL 0x034 ++#define ESPI_PERIF_NP_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_PERIF_NP_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_PERIF_NP_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_PERIF_NP_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_PERIF_NP_TX_DATA 0x038 ++#define ESPI_OOB_RX_DMA 0x040 ++#define ESPI_OOB_RX_CTRL 0x044 ++#define ESPI_OOB_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_OOB_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_OOB_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_OOB_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_OOB_RX_DATA 0x048 ++#define ESPI_OOB_TX_DMA 0x050 ++#define ESPI_OOB_TX_CTRL 0x054 ++#define ESPI_OOB_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_OOB_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_OOB_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_OOB_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_OOB_TX_DATA 0x058 ++#define ESPI_FLASH_RX_DMA 0x060 ++#define ESPI_FLASH_RX_CTRL 0x064 ++#define ESPI_FLASH_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_FLASH_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_FLASH_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_FLASH_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_FLASH_RX_DATA 0x068 ++#define ESPI_FLASH_TX_DMA 0x070 ++#define ESPI_FLASH_TX_CTRL 0x074 ++#define ESPI_FLASH_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_FLASH_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_FLASH_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_FLASH_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_FLASH_TX_DATA 0x078 ++#define ESPI_CTRL2 0x080 ++#define ESPI_CTRL2_VW_TX_SORT BIT(30) ++#define ESPI_CTRL2_MCYC_RD_DIS_WDT BIT(11) ++#define ESPI_CTRL2_MCYC_WR_DIS_WDT BIT(10) ++#define ESPI_CTRL2_MCYC_RD_DIS BIT(6) ++#define ESPI_CTRL2_MMBI_RD_DIS ESPI_CTRL2_MCYC_RD_DIS ++#define ESPI_CTRL2_MCYC_WR_DIS BIT(4) ++#define ESPI_CTRL2_MMBI_WR_DIS ESPI_CTRL2_MCYC_WR_DIS ++#define ESPI_PERIF_MCYC_SADDR 0x084 ++#define ESPI_PERIF_MMBI_SADDR ESPI_PERIF_MCYC_SADDR ++#define ESPI_PERIF_MCYC_TADDR 0x088 ++#define ESPI_PERIF_MMBI_TADDR ESPI_PERIF_MCYC_TADDR ++#define ESPI_PERIF_MCYC_MASK 0x08c ++#define ESPI_PERIF_MMBI_MASK ESPI_PERIF_MCYC_MASK ++#define ESPI_FLASH_EDAF_TADDR 0x090 ++#define ESPI_FLASH_EDAF_TADDR_BASE GENMASK(31, 24) ++#define ESPI_FLASH_EDAF_TADDR_MASK GENMASK(15, 8) ++#define ESPI_VW_SYSEVT_INT_EN 0x094 ++#define ESPI_VW_SYSEVT 0x098 ++#define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) ++#define ESPI_VW_SYSEVT_RST_CPU_INIT BIT(26) ++#define ESPI_VW_SYSEVT_SLV_BOOT_STS BIT(23) ++#define ESPI_VW_SYSEVT_NON_FATAL_ERR BIT(22) ++#define ESPI_VW_SYSEVT_FATAL_ERR BIT(21) ++#define ESPI_VW_SYSEVT_SLV_BOOT_DONE BIT(20) ++#define ESPI_VW_SYSEVT_OOB_RST_ACK BIT(16) ++#define ESPI_VW_SYSEVT_NMI_OUT BIT(10) ++#define ESPI_VW_SYSEVT_SMI_OUT BIT(9) ++#define ESPI_VW_SYSEVT_HOST_RST_WARN BIT(8) ++#define ESPI_VW_SYSEVT_OOB_RST_WARN BIT(6) ++#define ESPI_VW_SYSEVT_PLTRSTN BIT(5) ++#define ESPI_VW_SYSEVT_SUSPEND BIT(4) ++#define ESPI_VW_SYSEVT_S5_SLEEP BIT(2) ++#define ESPI_VW_SYSEVT_S4_SLEEP BIT(1) ++#define ESPI_VW_SYSEVT_S3_SLEEP BIT(0) ++#define ESPI_VW_GPIO_VAL 0x09c ++#define ESPI_GEN_CAP_N_CONF 0x0a0 ++#define ESPI_CH0_CAP_N_CONF 0x0a4 ++#define ESPI_CH1_CAP_N_CONF 0x0a8 ++#define ESPI_CH2_CAP_N_CONF 0x0ac ++#define ESPI_CH3_CAP_N_CONF 0x0b0 ++#define ESPI_CH3_CAP_N_CONF2 0x0b4 ++#define ESPI_VW_GPIO_DIR 0x0c0 ++#define ESPI_VW_GPIO_GRP 0x0c4 ++#define ESPI_INT_EN_CLR 0x0fc ++#define ESPI_VW_SYSEVT1_INT_EN 0x100 ++#define ESPI_VW_SYSEVT1 0x104 ++#define ESPI_VW_SYSEVT1_SUSPEND_ACK BIT(20) ++#define ESPI_VW_SYSEVT1_SUSPEND_WARN BIT(0) ++#define ESPI_VW_SYSEVT_INT_T0 0x110 ++#define ESPI_VW_SYSEVT_INT_T1 0x114 ++#define ESPI_VW_SYSEVT_INT_T2 0x118 ++#define ESPI_VW_SYSEVT_INT_STS 0x11c ++#define ESPI_VW_SYSEVT1_INT_T0 0x120 ++#define ESPI_VW_SYSEVT1_INT_T1 0x124 ++#define ESPI_VW_SYSEVT1_INT_T2 0x128 ++#define ESPI_VW_SYSEVT1_INT_STS 0x12c ++#define ESPI_OOB_RX_DESC_NUM 0x130 ++#define ESPI_OOB_RX_DESC_RPTR 0x134 ++#define ESPI_OOB_RX_DESC_RPTR_UPDATE BIT(31) ++#define ESPI_OOB_RX_DESC_RPTR_RP GENMASK(11, 0) ++#define ESPI_OOB_RX_DESC_WPTR 0x138 ++#define ESPI_OOB_RX_DESC_WPTR_RECV_EN BIT(31) ++#define ESPI_OOB_RX_DESC_WPTR_SP GENMASK(27, 16) ++#define ESPI_OOB_RX_DESC_WPTR_WP GENMASK(11, 0) ++#define ESPI_OOB_TX_DESC_NUM 0x140 ++#define ESPI_OOB_TX_DESC_RPTR 0x144 ++#define ESPI_OOB_TX_DESC_RPTR_UPDATE BIT(31) ++#define ESPI_OOB_TX_DESC_WPTR 0x148 ++#define ESPI_OOB_TX_DESC_WPTR_SEND_EN BIT(31) ++#define ESPI_MMBI_CTRL 0x800 ++#define ESPI_MMBI_CTRL_INST_SZ GENMASK(10, 8) ++#define ESPI_MMBI_CTRL_TOTAL_SZ GENMASK(6, 4) ++#define ESPI_MMBI_CTRL_EN BIT(0) ++#define ESPI_MMBI_INT_STS 0x808 ++#define ESPI_MMBI_INT_EN 0x80c ++#define ESPI_MMBI_HOST_RWP(x) (0x810 + ((x) << 3)) ++ ++/* collect ESPI_INT_EN bits for convenience */ ++#define ESPI_INT_EN_PERIF \ ++ (ESPI_INT_EN_PERIF_NP_TX_ABT | \ ++ ESPI_INT_EN_PERIF_PC_TX_ABT | \ ++ ESPI_INT_EN_PERIF_NP_RX_ABT | \ ++ ESPI_INT_EN_PERIF_PC_RX_ABT | \ ++ ESPI_INT_EN_PERIF_NP_TX_ERR | \ ++ ESPI_INT_EN_PERIF_PC_TX_ERR | \ ++ ESPI_INT_EN_PERIF_NP_TX_CMPLT | \ ++ ESPI_INT_EN_PERIF_PC_TX_CMPLT | \ ++ ESPI_INT_EN_PERIF_PC_RX_CMPLT) + -+ d = &oob->dma.rxd_virt[wptr]; ++#define ESPI_INT_EN_VW \ ++ (ESPI_INT_EN_VW_SYSEVT1 | \ ++ ESPI_INT_EN_VW_GPIO | \ ++ ESPI_INT_EN_VW_SYSEVT) + -+ if (!d->dirty) -+ return -EFAULT; ++#define ESPI_INT_EN_OOB \ ++ (ESPI_INT_EN_OOB_RX_TMOUT | \ ++ ESPI_INT_EN_OOB_TX_ERR | \ ++ ESPI_INT_EN_OOB_TX_ABT | \ ++ ESPI_INT_EN_OOB_RX_ABT | \ ++ ESPI_INT_EN_OOB_TX_CMPLT | \ ++ ESPI_INT_EN_OOB_RX_CMPLT) + -+ pkt_len = ((d->len) ? d->len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); ++#define ESPI_INT_EN_FLASH \ ++ (ESPI_INT_EN_FLASH_TX_ERR | \ ++ ESPI_INT_EN_FLASH_TX_ABT | \ ++ ESPI_INT_EN_FLASH_RX_ABT | \ ++ ESPI_INT_EN_FLASH_TX_CMPLT | \ ++ ESPI_INT_EN_FLASH_RX_CMPLT) + -+ if (ioc->pkt_len < pkt_len) -+ return -EINVAL; ++/* collect ESPI_INT_STS bits for convenience */ ++#define ESPI_INT_STS_PERIF \ ++ (ESPI_INT_STS_PERIF_NP_TX_ABT | \ ++ ESPI_INT_STS_PERIF_PC_TX_ABT | \ ++ ESPI_INT_STS_PERIF_NP_RX_ABT | \ ++ ESPI_INT_STS_PERIF_PC_RX_ABT | \ ++ ESPI_INT_STS_PERIF_NP_TX_ERR | \ ++ ESPI_INT_STS_PERIF_PC_TX_ERR | \ ++ ESPI_INT_STS_PERIF_NP_TX_CMPLT | \ ++ ESPI_INT_STS_PERIF_PC_TX_CMPLT | \ ++ ESPI_INT_STS_PERIF_PC_RX_CMPLT) + -+ pkt = vmalloc(pkt_len); -+ if (!pkt) -+ return -ENOMEM; ++#define ESPI_INT_STS_VW \ ++ (ESPI_INT_STS_VW_SYSEVT1 | \ ++ ESPI_INT_STS_VW_GPIO | \ ++ ESPI_INT_STS_VW_SYSEVT) + -+ hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = d->cyc; -+ hdr->tag = d->tag; -+ hdr->len_h = d->len >> 8; -+ hdr->len_l = d->len & 0xff; -+ memcpy(hdr + 1, oob->dma.rx_virt + (PAGE_SIZE * wptr), pkt_len - sizeof(*hdr)); ++#define ESPI_INT_STS_OOB \ ++ (ESPI_INT_STS_OOB_RX_TMOUT | \ ++ ESPI_INT_STS_OOB_TX_ERR | \ ++ ESPI_INT_STS_OOB_TX_ABT | \ ++ ESPI_INT_STS_OOB_RX_ABT | \ ++ ESPI_INT_STS_OOB_TX_CMPLT | \ ++ ESPI_INT_STS_OOB_RX_CMPLT) + -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++#define ESPI_INT_STS_FLASH \ ++ (ESPI_INT_STS_FLASH_TX_ERR | \ ++ ESPI_INT_STS_FLASH_TX_ABT | \ ++ ESPI_INT_STS_FLASH_RX_ABT | \ ++ ESPI_INT_STS_FLASH_TX_CMPLT | \ ++ ESPI_INT_STS_FLASH_RX_CMPLT) + -+ spin_lock_irqsave(&oob->lock, flags); + -+ /* make current descriptor available again */ -+ d->dirty = 0; ++/* consistent with DTS property "perif-mmbi-instance-size" */ ++enum ast2600_mmbi_instance_size { ++ MMBI_INST_SIZE_8KB = 0x0, ++ MMBI_INST_SIZE_16KB, ++ MMBI_INST_SIZE_32KB, ++ MMBI_INST_SIZE_64KB, ++ MMBI_INST_SIZE_128KB, ++ MMBI_INST_SIZE_256KB, ++ MMBI_INST_SIZE_512KB, ++ MMBI_INST_SIZE_1024KB, ++ MMBI_INST_SIZE_TYPES, ++}; + -+ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; -+ writel(wptr | ESPI_OOB_RX_DESC_WPTR_RECV_EN, espi->regs + ESPI_OOB_RX_DESC_WPTR); ++/* function operators */ ++void ast2600_espi_pre_init(struct aspeed_espi *espi); ++void ast2600_espi_post_init(struct aspeed_espi *espi); ++void ast2600_espi_deinit(struct aspeed_espi *espi); ++int ast2600_espi_perif_probe(struct aspeed_espi *espi); ++int ast2600_espi_perif_remove(struct aspeed_espi *espi); ++int ast2600_espi_vw_probe(struct aspeed_espi *espi); ++int ast2600_espi_vw_remove(struct aspeed_espi *espi); ++int ast2600_espi_oob_probe(struct aspeed_espi *espi); ++int ast2600_espi_oob_remove(struct aspeed_espi *espi); ++int ast2600_espi_flash_probe(struct aspeed_espi *espi); ++int ast2600_espi_flash_remove(struct aspeed_espi *espi); ++irqreturn_t ast2600_espi_isr(int irq, void *arg); ++#endif +diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/ast2700-espi.c +--- a/drivers/soc/aspeed/espi/ast2700-espi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2700-espi.c 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,1960 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#include "linux/err.h" ++#include "linux/fs.h" ++#include "linux/printk.h" ++#include "linux/spinlock.h" ++#include "linux/stddef.h" ++#include "linux/wait.h" ++#include "linux/kernel.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ /* set ready flag base on the next RX descriptor */ -+ oob->rx_ready = oob->dma.rxd_virt[wptr].dirty; ++#include "ast2700-espi.h" ++#include "aspeed-espi-comm.h" ++#include "aspeed-espi.h" + -+ spin_unlock_irqrestore(&oob->lock, flags); ++static DEFINE_IDA(ast2700_espi_ida); + -+ rc = 0; ++#define PERIF_MCYC_ALIGN SZ_64K + -+free_n_out: -+ vfree(pkt); ++#define OOB_DMA_RPTR_KEY 0x4f4f4253 ++#define OOB_DMA_DESC_NUM 8 ++#define OOB_DMA_DESC_CUSTOM 0x4 + -+ return rc; -+} ++#define FLASH_EDAF_ALIGN SZ_16M + -+static long ast2600_espi_oob_get_rx(struct file *fp, -+ struct ast2600_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++/* peripheral channel (CH0) */ ++static long ast2700_espi_perif_pc_get_rx(struct file *fp, ++ struct aspeed_espi_perif *perif, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; ++ u32 pkt_len; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(oob, struct ast2600_espi, oob); ++ espi = container_of(perif, struct aspeed_espi, perif); + + if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&oob->rx_mtx)) ++ if (!mutex_trylock(&perif->pc_rx_mtx)) + return -EAGAIN; + -+ if (!oob->rx_ready) { ++ if (!perif->rx_ready) { + rc = -ENODATA; + goto unlock_mtx_n_out; + } + } else { -+ mutex_lock(&oob->rx_mtx); ++ mutex_lock(&perif->pc_rx_mtx); + -+ if (!oob->rx_ready) { -+ rc = wait_event_interruptible(oob->wq, oob->rx_ready); ++ if (!perif->rx_ready) { ++ rc = wait_event_interruptible(perif->wq, perif->rx_ready); + if (rc == -ERESTARTSYS) { + rc = -EINTR; + goto unlock_mtx_n_out; @@ -69900,26 +71107,43 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + } + } + -+ if (oob->dma.enable) { -+ rc = ast2600_espi_oob_dma_get_rx(fp, oob, ioc); -+ goto unlock_mtx_n_out; -+ } -+ + /* + * common header (i.e. cycle type, tag, and length) + * part is written to HW registers + */ -+ reg = readl(espi->regs + ESPI_OOB_RX_CTRL); -+ cyc = FIELD_GET(ESPI_OOB_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_OOB_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_OOB_RX_CTRL_LEN, reg); ++ reg = readl(espi->regs + ESPI_CH0_PC_RX_CTRL); ++ cyc = FIELD_GET(ESPI_CH0_PC_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_CH0_PC_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_CH0_PC_RX_CTRL_LEN, reg); + + /* + * calculate the length of the rest part of the + * eSPI packet to be read from HW and copied to + * user space. + */ -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); ++ switch (cyc) { ++ case ESPI_PERIF_MSG: ++ pkt_len = sizeof(struct espi_perif_msg); ++ break; ++ case ESPI_PERIF_MSG_D: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_perif_msg); ++ break; ++ case ESPI_PERIF_SUC_CMPLT_D_MIDDLE: ++ case ESPI_PERIF_SUC_CMPLT_D_FIRST: ++ case ESPI_PERIF_SUC_CMPLT_D_LAST: ++ case ESPI_PERIF_SUC_CMPLT_D_ONLY: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_perif_cmplt); ++ break; ++ case ESPI_PERIF_SUC_CMPLT: ++ case ESPI_PERIF_UNSUC_CMPLT: ++ pkt_len = sizeof(struct espi_perif_cmplt); ++ break; ++ default: ++ rc = -EFAULT; ++ goto unlock_mtx_n_out; ++ } + + if (ioc->pkt_len < pkt_len) { + rc = -EINVAL; @@ -69938,20 +71162,24 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + hdr->len_h = len >> 8; + hdr->len_l = len & 0xff; + -+ for (i = sizeof(*hdr); i < pkt_len; ++i) -+ pkt[i] = readl(espi->regs + ESPI_OOB_RX_DATA) & 0xff; ++ if (perif->dma.enable) { ++ memcpy(hdr + 1, perif->dma.pc_rx_virt, pkt_len - sizeof(*hdr)); ++ } else { ++ for (i = sizeof(*hdr); i < pkt_len; ++i) ++ reg = readl(espi->regs + ESPI_CH0_PC_RX_DATA) & 0xff; ++ } + + if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { + rc = -EFAULT; + goto free_n_out; + } + -+ spin_lock_irqsave(&oob->lock, flags); ++ spin_lock_irqsave(&perif->lock, flags); + -+ writel(ESPI_OOB_RX_CTRL_SERV_PEND, espi->regs + ESPI_OOB_RX_CTRL); -+ oob->rx_ready = 0; ++ writel(ESPI_CH0_PC_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH0_PC_RX_CTRL); ++ perif->rx_ready = 0; + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ spin_unlock_irqrestore(&perif->lock, flags); + + rc = 0; + @@ -69959,494 +71187,103 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&oob->rx_mtx); -+ -+ return rc; -+} -+ -+static long ast2600_espi_oob_dma_put_tx(struct file *fp, -+ struct ast2600_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) -+{ -+ struct ast2600_espi_oob_dma_tx_desc *d; -+ struct ast2600_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint32_t rptr, wptr; -+ uint8_t *pkt; -+ int rc; -+ -+ espi = container_of(oob, struct ast2600_espi, oob); -+ -+ pkt = vzalloc(ioc->pkt_len); -+ if (!pkt) -+ return -ENOMEM; -+ -+ hdr = (struct espi_comm_hdr *)pkt; -+ -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } -+ -+ /* kick HW to update descriptor read/write pointer */ -+ writel(ESPI_OOB_TX_DESC_RPTR_UPDATE, espi->regs + ESPI_OOB_TX_DESC_RPTR); -+ -+ rptr = readl(espi->regs + ESPI_OOB_TX_DESC_RPTR); -+ wptr = readl(espi->regs + ESPI_OOB_TX_DESC_WPTR); -+ -+ if (((wptr + 1) % OOB_DMA_DESC_NUM) == rptr) { -+ rc = -EBUSY; -+ goto free_n_out; -+ } -+ -+ d = &oob->dma.txd_virt[wptr]; -+ d->cyc = hdr->cyc; -+ d->tag = hdr->tag; -+ d->len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -+ d->msg_type = OOB_DMA_DESC_CUSTOM; -+ -+ memcpy(oob->dma.tx_virt + (PAGE_SIZE * wptr), hdr + 1, ioc->pkt_len - sizeof(*hdr)); -+ -+ dma_wmb(); -+ -+ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; -+ writel(wptr | ESPI_OOB_TX_DESC_WPTR_SEND_EN, espi->regs + ESPI_OOB_TX_DESC_WPTR); -+ -+ rc = 0; -+ -+free_n_out: -+ vfree(pkt); ++ mutex_unlock(&perif->pc_rx_mtx); + + return rc; +} + -+static long ast2600_espi_oob_put_tx(struct file *fp, -+ struct ast2600_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static long ast2700_espi_perif_pc_put_tx(struct file *fp, ++ struct aspeed_espi_perif *perif, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(oob, struct ast2600_espi, oob); ++ espi = container_of(perif, struct aspeed_espi, perif); + -+ if (!mutex_trylock(&oob->tx_mtx)) ++ if (!mutex_trylock(&perif->pc_tx_mtx)) + return -EAGAIN; + -+ if (oob->dma.enable) { -+ rc = ast2600_espi_oob_dma_put_tx(fp, oob, ioc); -+ goto unlock_mtx_n_out; -+ } -+ -+ reg = readl(espi->regs + ESPI_OOB_TX_CTRL); -+ if (reg & ESPI_OOB_TX_CTRL_TRIG_PEND) { ++ reg = readl(espi->regs + ESPI_CH0_PC_TX_CTRL); ++ if (reg & ESPI_CH0_PC_TX_CTRL_TRIG_PEND) { + rc = -EBUSY; -+ goto unlock_mtx_n_out; -+ } -+ -+ if (ioc->pkt_len > ESPI_MAX_PKT_LEN) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; ++ goto unlock_n_out; + } + + pkt = vmalloc(ioc->pkt_len); + if (!pkt) { + rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } -+ -+ hdr = (struct espi_comm_hdr *)pkt; -+ -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } -+ -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_OOB_TX_DATA); -+ -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -+ -+ reg = FIELD_PREP(ESPI_OOB_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_OOB_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_OOB_TX_CTRL_LEN, len) -+ | ESPI_OOB_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_OOB_TX_CTRL); -+ -+ rc = 0; -+ -+free_n_out: -+ vfree(pkt); -+ -+unlock_mtx_n_out: -+ mutex_unlock(&oob->tx_mtx); -+ -+ return rc; -+} -+ -+static long ast2600_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -+{ -+ struct ast2600_espi_oob *oob; -+ struct aspeed_espi_ioc ioc; -+ -+ oob = container_of(fp->private_data, struct ast2600_espi_oob, mdev); -+ -+ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) -+ return -EFAULT; -+ -+ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) -+ return -EINVAL; -+ -+ switch (cmd) { -+ case ASPEED_ESPI_OOB_GET_RX: -+ return ast2600_espi_oob_get_rx(fp, oob, &ioc); -+ case ASPEED_ESPI_OOB_PUT_TX: -+ return ast2600_espi_oob_put_tx(fp, oob, &ioc); -+ }; -+ -+ return -EINVAL; -+} -+ -+static const struct file_operations ast2600_espi_oob_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2600_espi_oob_ioctl, -+}; -+ -+static void ast2600_espi_oob_isr(struct ast2600_espi *espi) -+{ -+ struct ast2600_espi_oob *oob; -+ unsigned long flags; -+ uint32_t sts; -+ -+ oob = &espi->oob; -+ -+ sts = readl(espi->regs + ESPI_INT_STS); -+ -+ if (sts & ESPI_INT_STS_OOB_RX_CMPLT) { -+ writel(ESPI_INT_STS_OOB_RX_CMPLT, espi->regs + ESPI_INT_STS); -+ -+ spin_lock_irqsave(&oob->lock, flags); -+ oob->rx_ready = true; -+ spin_unlock_irqrestore(&oob->lock, flags); -+ -+ wake_up_interruptible(&oob->wq); -+ } -+} -+ -+static void ast2600_espi_oob_reset(struct ast2600_espi *espi) -+{ -+ struct ast2600_espi_oob *oob; -+ dma_addr_t tx_addr, rx_addr; -+ uint32_t reg; -+ int i; -+ -+ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); -+ writel(ESPI_INT_STS_OOB, espi->regs + ESPI_INT_STS); -+ -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_OOB_TX_SW_RST -+ | ESPI_CTRL_OOB_RX_SW_RST -+ | ESPI_CTRL_OOB_TX_DMA_EN -+ | ESPI_CTRL_OOB_RX_DMA_EN -+ | ESPI_CTRL_OOB_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); -+ -+ udelay(1); -+ -+ reg |= (ESPI_CTRL_OOB_TX_SW_RST | ESPI_CTRL_OOB_RX_SW_RST); -+ writel(reg, espi->regs + ESPI_CTRL); -+ -+ oob = &espi->oob; -+ -+ if (oob->dma.enable) { -+ tx_addr = oob->dma.tx_addr; -+ rx_addr = oob->dma.rx_addr; -+ -+ for (i = 0; i < OOB_DMA_DESC_NUM; ++i) { -+ oob->dma.txd_virt[i].data_addr = tx_addr; -+ tx_addr += PAGE_SIZE; -+ -+ oob->dma.rxd_virt[i].data_addr = rx_addr; -+ oob->dma.rxd_virt[i].dirty = 0; -+ rx_addr += PAGE_SIZE; -+ } -+ -+ writel(oob->dma.txd_addr, espi->regs + ESPI_OOB_TX_DMA); -+ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_OOB_TX_DESC_RPTR); -+ writel(0x0, espi->regs + ESPI_OOB_TX_DESC_WPTR); -+ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_OOB_TX_DESC_NUM); -+ -+ writel(oob->dma.rxd_addr, espi->regs + ESPI_OOB_RX_DMA); -+ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_OOB_RX_DESC_RPTR); -+ writel(0x0, espi->regs + ESPI_OOB_RX_DESC_WPTR); -+ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_OOB_RX_DESC_NUM); -+ -+ reg = readl(espi->regs + ESPI_CTRL) -+ | ESPI_CTRL_OOB_TX_DMA_EN -+ | ESPI_CTRL_OOB_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CTRL); -+ -+ /* activate RX DMA to make OOB_FREE */ -+ writel(ESPI_OOB_RX_DESC_WPTR_RECV_EN, espi->regs + ESPI_OOB_RX_DESC_WPTR); -+ } -+ -+ writel(ESPI_INT_EN_OOB_RX_CMPLT, espi->regs + ESPI_INT_EN); -+ -+ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_OOB_SW_RDY; -+ writel(reg, espi->regs + ESPI_CTRL); -+} -+ -+static int ast2600_espi_oob_probe(struct ast2600_espi *espi) -+{ -+ struct ast2600_espi_oob *oob; -+ struct device *dev; -+ int rc; -+ -+ dev = espi->dev; -+ -+ oob = &espi->oob; -+ -+ init_waitqueue_head(&oob->wq); -+ -+ spin_lock_init(&oob->lock); -+ -+ mutex_init(&oob->tx_mtx); -+ mutex_init(&oob->rx_mtx); -+ -+ oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); -+ if (oob->dma.enable) { -+ oob->dma.txd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, &oob->dma.txd_addr, GFP_KERNEL); -+ if (!oob->dma.txd_virt) { -+ dev_err(dev, "cannot allocate DMA TX descriptor\n"); -+ return -ENOMEM; -+ } -+ oob->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.tx_addr, GFP_KERNEL); -+ if (!oob->dma.tx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); -+ return -ENOMEM; -+ } -+ -+ oob->dma.rxd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, &oob->dma.rxd_addr, GFP_KERNEL); -+ if (!oob->dma.rxd_virt) { -+ dev_err(dev, "cannot allocate DMA RX descriptor\n"); -+ return -ENOMEM; -+ } -+ -+ oob->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.rx_addr, GFP_KERNEL); -+ if (!oob->dma.rx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); -+ return -ENOMEM; -+ } -+ } -+ -+ oob->mdev.parent = dev; -+ oob->mdev.minor = MISC_DYNAMIC_MINOR; -+ oob->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-oob", DEVICE_NAME); -+ oob->mdev.fops = &ast2600_espi_oob_fops; -+ rc = misc_register(&oob->mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", oob->mdev.name); -+ return rc; -+ } -+ -+ ast2600_espi_oob_reset(espi); -+ -+ return 0; -+} -+ -+static int ast2600_espi_oob_remove(struct ast2600_espi *espi) -+{ -+ struct ast2600_espi_oob *oob; -+ struct device *dev; -+ uint32_t reg; -+ -+ dev = espi->dev; -+ -+ oob = &espi->oob; -+ -+ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); -+ -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_OOB_TX_DMA_EN -+ | ESPI_CTRL_OOB_RX_DMA_EN -+ | ESPI_CTRL_OOB_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); -+ -+ if (oob->dma.enable) { -+ dmam_free_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, -+ oob->dma.txd_virt, oob->dma.txd_addr); -+ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, -+ oob->dma.tx_virt, oob->dma.tx_addr); -+ dmam_free_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, -+ oob->dma.rxd_virt, oob->dma.rxd_addr); -+ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, -+ oob->dma.rx_virt, oob->dma.rx_addr); -+ } -+ -+ mutex_destroy(&oob->tx_mtx); -+ mutex_destroy(&oob->rx_mtx); -+ -+ misc_deregister(&oob->mdev); -+ -+ return 0; -+} -+ -+/* flash channel (CH3) */ -+static long ast2600_espi_flash_get_rx(struct file *fp, -+ struct ast2600_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) -+{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; -+ struct espi_comm_hdr *hdr; -+ unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; -+ int i, rc; -+ -+ rc = 0; -+ -+ espi = container_of(flash, struct ast2600_espi, flash); -+ -+ if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&flash->rx_mtx)) -+ return -EAGAIN; -+ -+ if (!flash->rx_ready) { -+ rc = -ENODATA; -+ goto unlock_mtx_n_out; -+ } -+ } else { -+ mutex_lock(&flash->rx_mtx); -+ -+ if (!flash->rx_ready) { -+ rc = wait_event_interruptible(flash->wq, flash->rx_ready); -+ if (rc == -ERESTARTSYS) { -+ rc = -EINTR; -+ goto unlock_mtx_n_out; -+ } -+ } -+ } -+ -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ reg = readl(espi->regs + ESPI_FLASH_RX_CTRL); -+ cyc = FIELD_GET(ESPI_FLASH_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_FLASH_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_FLASH_RX_CTRL_LEN, reg); -+ -+ /* -+ * calculate the length of the rest part of the -+ * eSPI packet to be read from HW and copied to -+ * user space. -+ */ -+ switch (cyc) { -+ case ESPI_FLASH_WRITE: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_flash_rwe); -+ break; -+ case ESPI_FLASH_READ: -+ case ESPI_FLASH_ERASE: -+ pkt_len = sizeof(struct espi_flash_rwe); -+ break; -+ case ESPI_FLASH_SUC_CMPLT_D_MIDDLE: -+ case ESPI_FLASH_SUC_CMPLT_D_FIRST: -+ case ESPI_FLASH_SUC_CMPLT_D_LAST: -+ case ESPI_FLASH_SUC_CMPLT_D_ONLY: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_flash_cmplt); -+ break; -+ case ESPI_FLASH_SUC_CMPLT: -+ case ESPI_FLASH_UNSUC_CMPLT: -+ pkt_len = sizeof(struct espi_flash_cmplt); -+ break; -+ default: -+ rc = -EFAULT; -+ goto unlock_mtx_n_out; -+ } -+ -+ if (ioc->pkt_len < pkt_len) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; -+ } -+ -+ pkt = vmalloc(pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; ++ goto unlock_n_out; + } + + hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = cyc; -+ hdr->tag = tag; -+ hdr->len_h = len >> 8; -+ hdr->len_l = len & 0xff; -+ -+ if (flash->dma.enable) { -+ memcpy(hdr + 1, flash->dma.rx_virt, pkt_len - sizeof(*hdr)); -+ } else { -+ for (i = sizeof(*hdr); i < pkt_len; ++i) -+ pkt[i] = readl(espi->regs + ESPI_FLASH_RX_DATA) & 0xff; -+ } + -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { + rc = -EFAULT; + goto free_n_out; + } + -+ spin_lock_irqsave(&flash->lock, flags); ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ if (perif->dma.enable) { ++ memcpy(perif->dma.pc_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ dma_wmb(); ++ } else { ++ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) ++ writel(pkt[i], espi->regs + ESPI_CH0_PC_TX_DATA); ++ } + -+ writel(ESPI_FLASH_RX_CTRL_SERV_PEND, espi->regs + ESPI_FLASH_RX_CTRL); -+ flash->rx_ready = 0; ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ spin_unlock_irqrestore(&flash->lock, flags); ++ reg = FIELD_PREP(ESPI_CH0_PC_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_CH0_PC_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_CH0_PC_TX_CTRL_LEN, len) ++ | ESPI_CH0_PC_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_CH0_PC_TX_CTRL); + + rc = 0; + +free_n_out: + vfree(pkt); + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->rx_mtx); ++unlock_n_out: ++ mutex_unlock(&perif->pc_tx_mtx); + + return rc; +} + -+static long ast2600_espi_flash_put_tx(struct file *fp, -+ struct ast2600_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) ++static long ast2700_espi_perif_np_put_tx(struct file *fp, ++ struct aspeed_espi_perif *perif, ++ struct aspeed_espi_ioc *ioc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2600_espi *espi; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; + struct espi_comm_hdr *hdr; -+ uint8_t *pkt; ++ u8 *pkt; + int i, rc; + -+ espi = container_of(flash, struct ast2600_espi, flash); ++ espi = container_of(perif, struct aspeed_espi, perif); + -+ if (!mutex_trylock(&flash->tx_mtx)) ++ if (!mutex_trylock(&perif->np_tx_mtx)) + return -EAGAIN; + -+ reg = readl(espi->regs + ESPI_FLASH_TX_CTRL); -+ if (reg & ESPI_FLASH_TX_CTRL_TRIG_PEND) { ++ reg = readl(espi->regs + ESPI_CH0_NP_TX_CTRL); ++ if (reg & ESPI_CH0_NP_TX_CTRL_TRIG_PEND) { + rc = -EBUSY; -+ goto unlock_mtx_n_out; ++ goto unlock_n_out; + } + + pkt = vmalloc(ioc->pkt_len); + if (!pkt) { + rc = -ENOMEM; -+ goto unlock_mtx_n_out; ++ goto unlock_n_out; + } + + hdr = (struct espi_comm_hdr *)pkt; @@ -70460,41 +71297,41 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + * common header (i.e. cycle type, tag, and length) + * part is written to HW registers + */ -+ if (flash->dma.enable) { -+ memcpy(flash->dma.tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ if (perif->dma.enable) { ++ memcpy(perif->dma.np_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); + dma_wmb(); + } else { + for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_FLASH_TX_DATA); ++ writel(pkt[i], espi->regs + ESPI_CH0_NP_TX_DATA); + } + + cyc = hdr->cyc; + tag = hdr->tag; + len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ reg = FIELD_PREP(ESPI_FLASH_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_FLASH_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_FLASH_TX_CTRL_LEN, len) -+ | ESPI_FLASH_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_FLASH_TX_CTRL); ++ reg = FIELD_PREP(ESPI_CH0_NP_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_CH0_NP_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_CH0_NP_TX_CTRL_LEN, len) ++ | ESPI_CH0_NP_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_CH0_NP_TX_CTRL); + + rc = 0; + +free_n_out: + vfree(pkt); + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->tx_mtx); ++unlock_n_out: ++ mutex_unlock(&perif->np_tx_mtx); + + return rc; +} + -+static long ast2600_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static long ast2700_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2600_espi_flash *flash; ++ struct aspeed_espi_perif *perif; + struct aspeed_espi_ioc ioc; + -+ flash = container_of(fp->private_data, struct ast2600_espi_flash, mdev); ++ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -70503,10 +71340,12 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + return -EINVAL; + + switch (cmd) { -+ case ASPEED_ESPI_FLASH_GET_RX: -+ return ast2600_espi_flash_get_rx(fp, flash, &ioc); -+ case ASPEED_ESPI_FLASH_PUT_TX: -+ return ast2600_espi_flash_put_tx(fp, flash, &ioc); ++ case ASPEED_ESPI_PERIF_PC_GET_RX: ++ return ast2700_espi_perif_pc_get_rx(fp, perif, &ioc); ++ case ASPEED_ESPI_PERIF_PC_PUT_TX: ++ return ast2700_espi_perif_pc_put_tx(fp, perif, &ioc); ++ case ASPEED_ESPI_PERIF_NP_PUT_TX: ++ return ast2700_espi_perif_np_put_tx(fp, perif, &ioc); + default: + break; + }; @@ -70514,4680 +71353,6032 @@ diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/ast2600-espi + return -EINVAL; +} + -+static const struct file_operations ast2600_espi_flash_fops = { ++static int ast2700_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) ++{ ++ struct aspeed_espi_perif *perif; ++ unsigned long vm_size; ++ pgprot_t vm_prot; ++ ++ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ if (!perif->mcyc.enable) ++ return -EPERM; ++ ++ vm_size = vma->vm_end - vma->vm_start; ++ vm_prot = vma->vm_page_prot; ++ ++ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > perif->mcyc.size) ++ return -EINVAL; ++ ++ vm_prot = pgprot_noncached(vm_prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, ++ (perif->mcyc.taddr >> PAGE_SHIFT) + vma->vm_pgoff, ++ vm_size, vm_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static const struct file_operations ast2700_espi_perif_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2600_espi_flash_ioctl, ++ .mmap = ast2700_espi_perif_mmap, ++ .unlocked_ioctl = ast2700_espi_perif_ioctl, +}; + -+static void ast2600_espi_flash_isr(struct ast2600_espi *espi) ++static void ast2700_espi_perif_isr(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_flash *flash; ++ struct aspeed_espi_perif *perif; + unsigned long flags; -+ uint32_t sts; ++ u32 sts; + -+ flash = &espi->flash; ++ perif = &espi->perif; + -+ sts = readl(espi->regs + ESPI_INT_STS); ++ sts = readl(espi->regs + ESPI_CH0_INT_STS); + -+ if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) { -+ writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); ++ if (sts & ESPI_CH0_INT_STS_PC_RX_CMPLT) { ++ writel(ESPI_CH0_INT_STS_PC_RX_CMPLT, espi->regs + ESPI_CH0_INT_STS); + -+ spin_lock_irqsave(&flash->lock, flags); -+ flash->rx_ready = true; -+ spin_unlock_irqrestore(&flash->lock, flags); ++ spin_lock_irqsave(&perif->lock, flags); ++ perif->rx_ready = true; ++ spin_unlock_irqrestore(&perif->lock, flags); + -+ wake_up_interruptible(&flash->wq); ++ wake_up_interruptible(&perif->wq); + } +} + -+static void ast2600_espi_flash_reset(struct ast2600_espi *espi) ++static void ast2700_espi_perif_sw_reset(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_flash *flash; -+ uint32_t reg; -+ -+ flash = &espi->flash; ++ struct device *dev; ++ u32 reg; + -+ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); -+ writel(ESPI_INT_STS_FLASH, espi->regs + ESPI_INT_STS); ++ dev = espi->dev; + -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_FLASH_TX_SW_RST -+ | ESPI_CTRL_FLASH_RX_SW_RST -+ | ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN -+ | ESPI_CTRL_FLASH_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); ++ reg = readl(espi->regs + ESPI_CH0_CTRL); ++ reg &= ~(ESPI_CH0_CTRL_NP_TX_RST ++ | ESPI_CH0_CTRL_NP_RX_RST ++ | ESPI_CH0_CTRL_PC_TX_RST ++ | ESPI_CH0_CTRL_PC_RX_RST ++ | ESPI_CH0_CTRL_NP_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_RX_DMA_EN ++ | ESPI_CH0_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH0_CTRL); + + udelay(1); + -+ reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); -+ writel(reg, espi->regs + ESPI_CTRL); ++ reg |= (ESPI_CH0_CTRL_NP_TX_RST ++ | ESPI_CH0_CTRL_NP_RX_RST ++ | ESPI_CH0_CTRL_PC_TX_RST ++ | ESPI_CH0_CTRL_PC_RX_RST); ++ writel(reg, espi->regs + ESPI_CH0_CTRL); ++} + -+ reg = readl(espi->regs + ESPI_CTRL) & ~ESPI_CTRL_FLASH_SAFS_MODE; -+ reg |= FIELD_PREP(ESPI_CTRL_FLASH_SAFS_MODE, flash->safs.mode); -+ writel(reg, espi->regs + ESPI_CTRL); ++static void ast2700_espi_perif_reset(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_perif *perif; ++ struct device *dev; ++ u64 mask; ++ u32 reg; + -+ if (flash->safs.mode == SAFS_MODE_MIX) { -+ reg = FIELD_PREP(ESPI_FLASH_SAFS_TADDR_BASE, flash->safs.taddr >> 24) -+ | FIELD_PREP(ESPI_FLASH_SAFS_TADDR_MASK, (~(flash->safs.size - 1)) >> 24); -+ writel(reg, espi->regs + ESPI_FLASH_SAFS_TADDR); ++ dev = espi->dev; ++ ++ perif = &espi->perif; ++ ++ writel(0x0, espi->regs + ESPI_CH0_INT_EN); ++ writel(0xffffffff, espi->regs + ESPI_CH0_INT_STS); ++ ++ reg = readl(espi->regs + ESPI_CH0_CTRL); ++ reg &= ~(ESPI_CH0_CTRL_MCYC_RD_DIS_WDT | ESPI_CH0_CTRL_MCYC_WR_DIS_WDT); ++ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ ++ reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL); ++ reg &= ~ESPI_CH0_MCYC1_MASKL_EN; ++ writel(reg, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ ++ reg = readl(espi->regs + ESPI_CH0_CTRL); ++ reg |= (ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); ++ reg &= ~(ESPI_CH0_CTRL_NP_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_RX_DMA_EN ++ | ESPI_CH0_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ ++ if (perif->mcyc.enable) { ++ mask = ~(perif->mcyc.size - 1); ++ writel(upper_32_bits(mask), espi->regs + ESPI_CH0_MCYC1_MASKH); ++ writel(mask & 0xffffffff, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ writel(upper_32_bits(perif->mcyc.saddr), espi->regs + ESPI_CH0_MCYC1_SADDRH); ++ writel((perif->mcyc.saddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC1_SADDRL); ++ writel(upper_32_bits(perif->mcyc.taddr), espi->regs + ESPI_CH0_MCYC1_TADDRH); ++ writel((perif->mcyc.taddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC1_TADDRL); ++ ++ reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL) | ESPI_CH0_MCYC1_MASKL_EN; ++ writel(reg, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ ++ reg = readl(espi->regs + ESPI_CH0_CTRL); ++ reg &= ~(ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); ++ writel(reg, espi->regs + ESPI_CH0_CTRL); + } + -+ if (flash->dma.enable) { -+ writel(flash->dma.tx_addr, espi->regs + ESPI_FLASH_TX_DMA); -+ writel(flash->dma.rx_addr, espi->regs + ESPI_FLASH_RX_DMA); ++ if (perif->dma.enable) { ++ writel(upper_32_bits(perif->dma.np_tx_addr), espi->regs + ESPI_CH0_NP_TX_DMAH); ++ writel((perif->dma.np_tx_addr & 0xffffffff), espi->regs + ESPI_CH0_NP_TX_DMAL); ++ writel(upper_32_bits(perif->dma.pc_tx_addr), espi->regs + ESPI_CH0_PC_TX_DMAH); ++ writel((perif->dma.pc_tx_addr & 0xffffffff), espi->regs + ESPI_CH0_PC_TX_DMAL); ++ writel(upper_32_bits(perif->dma.pc_rx_addr), espi->regs + ESPI_CH0_PC_RX_DMAH); ++ writel((perif->dma.pc_rx_addr & 0xffffffff), espi->regs + ESPI_CH0_PC_RX_DMAL); + -+ reg = readl(espi->regs + ESPI_CTRL) -+ | ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CTRL); ++ reg = readl(espi->regs + ESPI_CH0_CTRL) ++ | ESPI_CH0_CTRL_NP_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_RX_DMA_EN; ++ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ } ++ if (perif->rtc_enable) { ++ reg = readl(espi->regs + ESPI_CAP_GEN) ++ | ESPI_CAP_GEN_RTC_SUP; ++ writel(reg, espi->regs + ESPI_CAP_GEN); + } + -+ writel(ESPI_INT_EN_FLASH_RX_CMPLT, espi->regs + ESPI_INT_EN); ++ writel(ESPI_CH0_INT_EN_PC_RX_CMPLT, espi->regs + ESPI_CH0_INT_EN); + -+ reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SW_RDY; -+ writel(reg, espi->regs + ESPI_CTRL); ++ reg = readl(espi->regs + ESPI_CH0_CTRL) | ESPI_CH0_CTRL_SW_RDY; ++ writel(reg, espi->regs + ESPI_CH0_CTRL); +} + -+static int ast2600_espi_flash_probe(struct ast2600_espi *espi) ++int ast2700_espi_perif_probe(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_flash *flash; ++ struct aspeed_espi_perif *perif; ++ struct device_node *np; + struct device *dev; ++ u64 temp; + int rc; + + dev = espi->dev; + -+ flash = &espi->flash; -+ -+ init_waitqueue_head(&flash->wq); ++ perif = &espi->perif; + -+ spin_lock_init(&flash->lock); ++ init_waitqueue_head(&perif->wq); + -+ mutex_init(&flash->tx_mtx); -+ mutex_init(&flash->rx_mtx); ++ spin_lock_init(&perif->lock); + -+ flash->safs.mode = SAFS_MODE_HW; ++ mutex_init(&perif->np_tx_mtx); ++ mutex_init(&perif->pc_tx_mtx); ++ mutex_init(&perif->pc_rx_mtx); + -+ of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->safs.mode); -+ if (flash->safs.mode == SAFS_MODE_MIX) { -+ rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", &flash->safs.taddr); -+ if (rc || !IS_ALIGNED(flash->safs.taddr, FLASH_SAFS_ALIGN)) { -+ dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); ++ perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); ++ if (perif->mcyc.enable) { ++ rc = of_property_read_u64(dev->of_node, "perif-mcyc-src-addr", &temp); ++ if (rc || !IS_ALIGNED(temp, PERIF_MCYC_ALIGN)) { ++ dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); + return -ENODEV; + } ++ perif->mcyc.saddr = temp; + -+ rc = of_property_read_u32(dev->of_node, "flash-safs-size", &flash->safs.size); -+ if (rc || !IS_ALIGNED(flash->safs.size, FLASH_SAFS_ALIGN)) { -+ dev_err(dev, "cannot get 16MB-aligned SAFS size\n"); -+ return -ENODEV; ++ rc = of_property_read_u64(dev->of_node, "perif-mcyc-size", &temp); ++ if (rc || !IS_ALIGNED(temp, PERIF_MCYC_ALIGN)) { ++ dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); ++ return -EINVAL; ++ } ++ perif->mcyc.size = temp; ++ ++ np = of_parse_phandle(dev->of_node, "memory-region", 0); ++ if (np) { ++ of_reserved_mem_device_init(dev); ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ dev_err(dev, "Failed to mask DMA.\n"); ++ return -ENODEV; ++ } ++ } ++ ++ perif->mcyc.virt = dmam_alloc_coherent(dev, perif->mcyc.size, ++ &perif->mcyc.taddr, GFP_KERNEL); ++ if (!perif->mcyc.virt) { ++ dev_err(dev, "cannot allocate memory cycle\n"); ++ return -ENOMEM; + } + } + -+ flash->dma.enable = of_property_read_bool(dev->of_node, "flash-dma-mode"); -+ if (flash->dma.enable) { -+ flash->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.tx_addr, GFP_KERNEL); -+ if (!flash->dma.tx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ perif->dma.enable = of_property_read_bool(dev->of_node, "perif-dma-mode"); ++ if (perif->dma.enable) { ++ perif->dma.pc_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, ++ &perif->dma.pc_tx_addr, GFP_KERNEL); ++ if (!perif->dma.pc_tx_virt) { ++ dev_err(dev, "cannot allocate posted TX DMA buffer\n"); + return -ENOMEM; + } + -+ flash->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.rx_addr, GFP_KERNEL); -+ if (!flash->dma.rx_virt) { -+ dev_err(dev, "cannot allocate DMA RX buffer\n"); ++ perif->dma.pc_rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, ++ &perif->dma.pc_rx_addr, GFP_KERNEL); ++ if (!perif->dma.pc_rx_virt) { ++ dev_err(dev, "cannot allocate posted RX DMA buffer\n"); ++ return -ENOMEM; ++ } ++ ++ perif->dma.np_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, ++ &perif->dma.np_tx_addr, GFP_KERNEL); ++ if (!perif->dma.np_tx_virt) { ++ dev_err(dev, "cannot allocate non-posted TX DMA buffer\n"); + return -ENOMEM; + } + } ++ perif->rtc_enable = of_property_read_bool(dev->of_node, "perif-rtc-enable"); + -+ flash->mdev.parent = dev; -+ flash->mdev.minor = MISC_DYNAMIC_MINOR; -+ flash->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-flash", DEVICE_NAME); -+ flash->mdev.fops = &ast2600_espi_flash_fops; -+ rc = misc_register(&flash->mdev); ++ perif->mdev.parent = dev; ++ perif->mdev.minor = MISC_DYNAMIC_MINOR; ++ perif->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-peripheral%d", DEVICE_NAME, espi->dev_id); ++ perif->mdev.fops = &ast2700_espi_perif_fops; ++ rc = misc_register(&perif->mdev); + if (rc) { -+ dev_err(dev, "cannot register device %s\n", flash->mdev.name); ++ dev_err(dev, "cannot register device %s\n", perif->mdev.name); + return rc; + } + -+ ast2600_espi_flash_reset(espi); ++ ast2700_espi_perif_reset(espi); + ++ of_platform_populate(dev->of_node, NULL, NULL, dev); + return 0; +} + -+static int ast2600_espi_flash_remove(struct ast2600_espi *espi) ++int ast2700_espi_perif_remove(struct aspeed_espi *espi) +{ -+ struct ast2600_espi_flash *flash; ++ struct aspeed_espi_perif *perif; + struct device *dev; -+ uint32_t reg; ++ u32 reg; + + dev = espi->dev; + -+ flash = &espi->flash; ++ perif = &espi->perif; + -+ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); ++ writel(0x0, espi->regs + ESPI_CH0_INT_EN); + -+ reg = readl(espi->regs + ESPI_CTRL); -+ reg &= ~(ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN -+ | ESPI_CTRL_FLASH_SW_RDY); -+ writel(reg, espi->regs + ESPI_CTRL); ++ reg = readl(espi->regs + ESPI_CH0_MCYC0_MASKL); ++ reg &= ~ESPI_CH0_MCYC0_MASKL_EN; ++ writel(reg, espi->regs + ESPI_CH0_MCYC0_MASKL); + -+ if (flash->dma.enable) { -+ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.rx_addr); ++ reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL); ++ reg &= ~ESPI_CH0_MCYC1_MASKL_EN; ++ writel(reg, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ ++ reg = readl(espi->regs + ESPI_CH0_CTRL); ++ reg |= (ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); ++ reg &= ~(ESPI_CH0_CTRL_NP_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_RX_DMA_EN ++ | ESPI_CH0_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ ++ if (perif->mcyc.enable) ++ dmam_free_coherent(dev, perif->mcyc.size, perif->mcyc.virt, ++ perif->mcyc.taddr); ++ ++ if (perif->dma.enable) { ++ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.np_tx_virt, ++ perif->dma.np_tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_tx_virt, ++ perif->dma.pc_tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_rx_virt, ++ perif->dma.pc_rx_addr); + } + -+ mutex_destroy(&flash->tx_mtx); -+ mutex_destroy(&flash->rx_mtx); ++ mutex_destroy(&perif->np_tx_mtx); ++ mutex_destroy(&perif->pc_tx_mtx); ++ mutex_destroy(&perif->pc_rx_mtx); + -+ misc_deregister(&flash->mdev); ++ misc_deregister(&perif->mdev); + + return 0; +} + -+/* global control */ -+static irqreturn_t ast2600_espi_isr(int irq, void *arg) ++/* virtual wire channel (CH1) */ ++static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct ast2600_espi *espi; -+ uint32_t sts; ++ struct aspeed_espi_vw *vw; ++ struct aspeed_espi *espi; ++ u32 gpio0, gpio1; ++ u8 pch_generic; ++ u32 reg; ++ u32 hw_mode; + -+ espi = (struct ast2600_espi *)arg; ++ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); ++ espi = container_of(vw, struct aspeed_espi, vw); ++ gpio0 = vw->gpio.val0; ++ gpio1 = vw->gpio.val1; ++ hw_mode = vw->gpio.hw_mode; ++ pch_generic = vw->platform.pch_generic; + -+ sts = readl(espi->regs + ESPI_INT_STS); -+ if (!sts) -+ return IRQ_NONE; ++ if (hw_mode) { ++ dev_err(espi->dev, "HW mode: vGPIO reflect on physical GPIO. Get state from GPIO driver.\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_PERIF) -+ ast2600_espi_perif_isr(espi); ++ switch (cmd) { ++ case ASPEED_ESPI_VW_GET_GPIO_VAL: ++ if (put_user(gpio0, (u32 __user *)arg)) { ++ dev_err(espi->dev, "failed to get vGPIO value0\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_VW) -+ ast2600_espi_vw_isr(espi); ++ dev_info(espi->dev, "Get vGPIO value0: 0x%x\n", gpio0); ++ break; + -+ if (sts & ESPI_INT_STS_OOB) -+ ast2600_espi_oob_isr(espi); ++ case ASPEED_ESPI_VW_PUT_GPIO_VAL: ++ if (get_user(gpio0, (u32 __user *)arg)) { ++ dev_err(espi->dev, "failed to put vGPIO value0\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_FLASH) -+ ast2600_espi_flash_isr(espi); ++ dev_info(espi->dev, "Put vGPIO value0: 0x%x\n", gpio0); ++ writel(gpio0, espi->regs + ESPI_CH1_GPIO_VAL0); ++ break; ++#ifdef CONFIG_ARM64 ++ case ASPEED_ESPI_VW_GET_GPIO_VAL1: ++ if (put_user(gpio1, (u32 __user *)arg)) { ++ dev_err(espi->dev, "failed to get vGPIO value1\n"); ++ return -EFAULT; ++ } + -+ if (sts & ESPI_INT_STS_RST_DEASSERT) { -+ /* this will clear all interrupt enable and status */ -+ reset_control_assert(espi->rst); -+ reset_control_deassert(espi->rst); ++ dev_info(espi->dev, "Get vGPIO value1: 0x%x\n", gpio1); ++ break; + -+ ast2600_espi_perif_sw_reset(espi); -+ ast2600_espi_perif_reset(espi); -+ ast2600_espi_vw_reset(espi); -+ ast2600_espi_oob_reset(espi); -+ ast2600_espi_flash_reset(espi); ++ case ASPEED_ESPI_VW_PUT_GPIO_VAL1: ++ if (get_user(gpio1, (u32 __user *)arg)) { ++ dev_err(espi->dev, "failed to put vGPIO value1\n"); ++ return -EFAULT; ++ } + -+ /* re-enable eSPI_RESET# interrupt */ -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); -+ } ++ dev_info(espi->dev, "Put vGPIO value1: 0x%x\n", gpio1); ++ writel(gpio1, espi->regs + ESPI_CH1_GPIO_VAL1); ++ break; ++#endif ++ case ASPEED_ESPI_VW_GET_PCH_GENERIC: ++ if (put_user(pch_generic, (u8 __user *)arg)) { ++ dev_err(espi->dev, "failed to get PCH generic event status\n"); ++ return -EFAULT; ++ } + -+ return IRQ_HANDLED; ++ dev_info(espi->dev, "Get PCH generic event status: 0x%x\n", pch_generic); ++ break; ++ case ASPEED_ESPI_VW_PUT_PCH_GENERIC: ++ if (get_user(pch_generic, (u8 __user *)arg)) { ++ dev_err(espi->dev, "failed to put PCH generic event status\n"); ++ return -EFAULT; ++ } ++ ++ dev_info(espi->dev, "Put PCH generic event status: 0x%x\n", pch_generic); ++ reg = readl(espi->regs + ESPI_CH1_EVT1); ++ reg &= ~ESPI_CH1_EVT1_BMC_GENE; ++ reg |= FIELD_PREP(ESPI_CH1_EVT1_BMC_GENE, pch_generic); ++ writel(reg, espi->regs + ESPI_CH1_EVT1); ++ break; ++ default: ++ return -EINVAL; ++ }; ++ ++ return 0; +} + -+static int ast2600_espi_probe(struct platform_device *pdev) ++static const struct file_operations ast2700_espi_vw_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2700_espi_vw_ioctl, ++}; ++ ++static inline struct aspeed_espi_vw *to_ast2700_espi_pltrst(struct file *filp) +{ -+ struct ast2600_espi *espi; -+ struct resource *res; -+ struct device *dev; -+ int rc; ++ return container_of(filp->private_data, struct aspeed_espi_vw, ++ pltrst_mdev); ++} + -+ dev = &pdev->dev; ++static int ast2700_espi_vw_pltrst_open(struct inode *inode, struct file *filp) ++{ ++ struct aspeed_espi_vw *priv = to_ast2700_espi_pltrst(filp); + -+ espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -+ if (!espi) -+ return -ENOMEM; ++ if ((filp->f_flags & O_ACCMODE) != O_RDONLY) ++ return -EACCES; ++ priv->pltrst.pltrst_avail = true ; /*Setting true returns first data after file open*/ + -+ espi->dev = dev; ++ return 0; ++} + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; -+ } ++static ssize_t ast2700_espi_vw_pltrst_read(struct file *filp, char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct aspeed_espi_vw *vw = to_ast2700_espi_pltrst(filp); ++ DECLARE_WAITQUEUE(wait, current); ++ char data, old_sample; ++ int ret = 0; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(dev, "cannot get resource\n"); -+ return -ENODEV; -+ } ++ spin_lock_irq(&vw->pltrst.pltrst_lock); + -+ espi->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(espi->regs)) { -+ dev_err(dev, "cannot map registers\n"); -+ return PTR_ERR(espi->regs); ++ if (filp->f_flags & O_NONBLOCK) { ++ if (!vw->pltrst.pltrst_avail) { ++ ret = -EAGAIN; ++ goto out_unlock; ++ } ++ data = vw->pltrst.pltrst_status; ++ vw->pltrst.pltrst_avail = false; ++ } else { ++ add_wait_queue(&vw->pltrst.pltrst_wq, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ old_sample = vw->pltrst.pltrst_status; ++ ++ do { ++ if (old_sample != vw->pltrst.pltrst_status) { ++ data = vw->pltrst.pltrst_status; ++ vw->pltrst.pltrst_avail = false; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ } else { ++ spin_unlock_irq(&vw->pltrst.pltrst_lock); ++ schedule(); ++ spin_lock_irq(&vw->pltrst.pltrst_lock); ++ } ++ } while (!ret); ++ ++ remove_wait_queue(&vw->pltrst.pltrst_wq, &wait); ++ set_current_state(TASK_RUNNING); + } ++out_unlock: ++ spin_unlock_irq(&vw->pltrst.pltrst_lock); ++ if (ret) ++ return ret; + -+ espi->irq = platform_get_irq(pdev, 0); -+ if (espi->irq < 0) { -+ dev_err(dev, "cannot get IRQ number\n"); -+ return -ENODEV; ++ ret = put_user(data, buf); ++ if (!ret) ++ ret = sizeof(data); ++ ++ return ret; ++} ++ ++static unsigned int ast2700_espi_vw_pltrst_poll(struct file *file, ++ poll_table *wait) ++{ ++ struct aspeed_espi_vw *vw = to_ast2700_espi_pltrst(file); ++ unsigned int mask = 0; ++ ++ poll_wait(file, &vw->pltrst.pltrst_wq, wait); ++ if (vw->pltrst.pltrst_avail) ++ mask |= POLLIN; ++ return mask; ++} ++ ++static const struct file_operations ast2700_espi_vw_pltrst_fops = { ++ .owner = THIS_MODULE, ++ .open = ast2700_espi_vw_pltrst_open, ++ .read = ast2700_espi_vw_pltrst_read, ++ .poll = ast2700_espi_vw_pltrst_poll, ++}; ++ ++static void ast2700_espi_vw_isr(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_vw *vw; ++ u32 sts_evt; ++ u32 sts; ++ u32 evt; ++ unsigned long flags; ++ ++ vw = &espi->vw; ++ ++ sts = readl(espi->regs + ESPI_CH1_INT_STS); ++ ++ if (sts & ESPI_CH1_INT_STS_GPIO) { ++ vw->gpio.val0 = readl(espi->regs + ESPI_CH1_GPIO_VAL0); ++ vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); ++ /* Workaround for AST2700 VW INT_STS */ ++ writel(ESPI_CH1_INT_STS_GPIO_CLR, espi->regs + ESPI_CH1_INT_STS); + } + -+ espi->rst = devm_reset_control_get_exclusive_by_index(dev, 0); -+ if (IS_ERR(espi->rst)) { -+ dev_err(dev, "cannot get reset control\n"); -+ return PTR_ERR(espi->rst); -+ } ++ if (sts & ESPI_CH1_INT_STS_EVT1) { ++ sts_evt = readl(espi->regs + ESPI_CH1_EVT1_INT_STS); ++ if (sts_evt & ESPI_CH1_EVT1_INT_STS_PCH_GENE) { ++ vw->platform.pch_generic = FIELD_GET(ESPI_CH1_EVT1_PCH_GENE, ++ readl(espi->regs + ESPI_CH1_EVT1)); + -+ espi->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(espi->clk)) { -+ dev_err(dev, "cannot get clock control\n"); -+ return PTR_ERR(espi->clk); -+ } ++ writel(ESPI_CH1_EVT1_INT_STS_PCH_GENE, ++ espi->regs + ESPI_CH1_EVT1_INT_STS); ++ } + -+ rc = clk_prepare_enable(espi->clk); -+ if (rc) { -+ dev_err(dev, "cannot enable clocks\n"); -+ return rc; ++ writel(ESPI_CH1_INT_STS_EVT1_CLR, espi->regs + ESPI_CH1_INT_STS); + } + -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); ++ if (sts & ESPI_CH1_INT_STS_EVT0) { ++ sts_evt = readl(espi->regs + ESPI_CH1_EVT0_INT_STS); ++ evt = readl(espi->regs + ESPI_CH1_EVT0); ++ if (sts_evt & ESPI_CH1_EVT0_INT_STS_PLTRSTN || vw->pltrst.pltrst_status == 'U') { ++ spin_lock_irqsave(&vw->pltrst.pltrst_lock, flags); ++ vw->pltrst.pltrst_status = (evt & ESPI_CH1_EVT0_PLTRSTN) ? '1' : '0'; ++ vw->pltrst.pltrst_avail = true; ++ spin_unlock_irqrestore(&vw->pltrst.pltrst_lock, flags); + -+ rc = ast2600_espi_perif_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); -+ return rc; -+ } ++ writel(ESPI_CH1_EVT0_INT_STS_PLTRSTN, ++ espi->regs + ESPI_CH1_EVT0_INT_STS); + -+ rc = ast2600_espi_vw_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init vw channel, rc=%d\n", rc); -+ goto err_remove_perif; ++ wake_up_interruptible(&vw->pltrst.pltrst_wq); ++ } ++ writel(ESPI_CH1_INT_STS_EVT0, espi->regs + ESPI_CH1_INT_STS); + } ++} + -+ rc = ast2600_espi_oob_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init oob channel, rc=%d\n", rc); -+ goto err_remove_vw; ++static void ast2700_espi_vw_reset(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ struct aspeed_espi_vw *vw = &espi->vw; ++ ++ writel(0x0, espi->regs + ESPI_CH1_INT_EN); ++ writel(0xffffffff, espi->regs + ESPI_CH1_INT_STS); ++ ++ writel(vw->gpio.grp, espi->regs + ESPI_CH1_GPIO_GRP); ++ writel(vw->gpio.dir0, espi->regs + ESPI_CH1_GPIO_DIR0); ++ writel(vw->gpio.dir1, espi->regs + ESPI_CH1_GPIO_DIR1); ++ ++ vw->gpio.val0 = readl(espi->regs + ESPI_CH1_GPIO_VAL0); ++ vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); ++ vw->platform.pch_generic = FIELD_GET(ESPI_CH1_EVT1_PCH_GENE, ++ readl(espi->regs + ESPI_CH1_EVT1)); ++ ++ writel(ESPI_CH1_EVT1_INT_T2_PCH_GENE, ++ espi->regs + ESPI_CH1_EVT1_INT_T2); ++ writel(ESPI_CH1_EVT1_INT_EN_PCH_GENE, espi->regs + ESPI_CH1_EVT1_INT_EN); ++ ++ if (vw->pltrst.enabled) { ++ spin_lock(&vw->pltrst.pltrst_lock); ++ vw->pltrst.pltrst_status = 'U'; /* Unknown */ ++ vw->pltrst.pltrst_avail = true; ++ spin_unlock(&vw->pltrst.pltrst_lock); ++ ++ writel(ESPI_CH1_EVT0_INT_T2_PLTRSTN, ++ espi->regs + ESPI_CH1_EVT0_INT_T2); ++ writel(ESPI_CH1_EVT0_INT_EN_PLTRSTN, espi->regs + ESPI_CH1_EVT0_INT_EN); ++ writel(ESPI_CH1_INT_EN_GPIO | ESPI_CH1_INT_EN_SYS_EVT1 | ESPI_CH1_INT_EN_SYS_EVT0, ++ espi->regs + ESPI_CH1_INT_EN); ++ } else { ++ writel(ESPI_CH1_INT_EN_GPIO | ESPI_CH1_INT_EN_SYS_EVT1, espi->regs + ESPI_CH1_INT_EN); + } + -+ rc = ast2600_espi_flash_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init flash channel, rc=%d\n", rc); -+ goto err_remove_oob; ++ reg = readl(espi->regs + ESPI_CH1_CTRL) ++ | ((vw->gpio.hw_mode) ? ESPI_CH1_CTRL_GPIO_HW : 0) ++ | ESPI_CH1_CTRL_SW_RDY; ++ writel(reg, espi->regs + ESPI_CH1_CTRL); ++} ++ ++int ast2700_espi_vw_probe(struct aspeed_espi *espi) ++{ ++ int rc; ++ struct device *dev = espi->dev; ++ struct aspeed_espi_vw *vw = &espi->vw; ++ ++ vw->gpio.hw_mode = of_property_read_bool(dev->of_node, "vw-gpio-hw-mode"); ++ of_property_read_u32(dev->of_node, "vw-gpio-group", &vw->gpio.grp); ++ of_property_read_u32_index(dev->of_node, "vw-gpio-direction", 0, &vw->gpio.dir0); ++ of_property_read_u32_index(dev->of_node, "vw-gpio-direction", 1, &vw->gpio.dir1); ++ ++ vw->pltrst.enabled = of_property_read_bool(dev->of_node, "vw-pltrst-monitor"); ++ if (vw->pltrst.enabled) { ++ spin_lock_init(&vw->pltrst.pltrst_lock); ++ init_waitqueue_head(&vw->pltrst.pltrst_wq); ++ vw->pltrst.pltrst_status = 'U'; /* Unknown */ ++ vw->pltrst.pltrst_avail = false; ++ vw->pltrst_mdev.parent = dev; ++ vw->pltrst_mdev.minor = MISC_DYNAMIC_MINOR; ++ vw->pltrst_mdev.name = ++ devm_kasprintf(dev, GFP_KERNEL, "%s-pltrstn%d", ++ DEVICE_NAME, espi->dev_id); ++ vw->pltrst_mdev.fops = &ast2700_espi_vw_pltrst_fops; ++ rc = misc_register(&vw->pltrst_mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", vw->pltrst_mdev.name); ++ return rc; ++ } + } + -+ rc = devm_request_irq(dev, espi->irq, ast2600_espi_isr, 0, dev_name(dev), espi); ++ vw->mdev.parent = dev; ++ vw->mdev.minor = MISC_DYNAMIC_MINOR; ++ vw->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-vw%d", DEVICE_NAME, espi->dev_id); ++ vw->mdev.fops = &ast2700_espi_vw_fops; ++ rc = misc_register(&vw->mdev); + if (rc) { -+ dev_err(dev, "cannot request IRQ\n"); -+ goto err_remove_flash; ++ dev_err(dev, "cannot register device %s\n", vw->mdev.name); ++ return rc; + } + -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); ++ ast2700_espi_vw_reset(espi); + -+ platform_set_drvdata(pdev, espi); ++ return 0; ++} + -+ dev_info(dev, "module loaded\n"); ++int ast2700_espi_vw_remove(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_vw *vw; + -+ return 0; ++ vw = &espi->vw; + -+err_remove_flash: -+ ast2600_espi_flash_remove(espi); -+err_remove_oob: -+ ast2600_espi_oob_remove(espi); -+err_remove_vw: -+ ast2600_espi_vw_remove(espi); -+err_remove_perif: -+ ast2600_espi_perif_remove(espi); ++ writel(0x0, espi->regs + ESPI_CH1_INT_EN); + -+ return rc; ++ misc_deregister(&vw->mdev); ++ ++ return 0; +} + -+static void ast2600_espi_remove(struct platform_device *pdev) ++/* out-of-band channel (CH2) */ ++static long ast2700_espi_oob_dma_get_rx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) +{ -+ struct ast2600_espi *espi; -+ struct device *dev; ++ struct ast2700_espi_oob_dma_rx_desc *d; ++ struct ast2700_espi_oob_dma_rx_desc *rx_descs; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u32 wptr, pkt_len; ++ unsigned long flags; ++ u8 *pkt; + int rc; + -+ dev = &pdev->dev; ++ espi = container_of(oob, struct aspeed_espi, oob); + -+ espi = platform_get_drvdata(pdev); ++ wptr = FIELD_PREP(ESPI_CH2_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_CH2_RX_DESC_WPTR)); + -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); ++ rx_descs = (struct ast2700_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; ++ d = &rx_descs[wptr]; + -+ rc = ast2600_espi_perif_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ if (!d->dirty) ++ return -EFAULT; + -+ rc = ast2600_espi_vw_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ pkt_len = ((d->len) ? d->len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); + -+ rc = ast2600_espi_oob_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ if (ioc->pkt_len < pkt_len) ++ return -EINVAL; + -+ rc = ast2600_espi_flash_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -+} ++ pkt = vmalloc(pkt_len); ++ if (!pkt) ++ return -ENOMEM; + -+static const struct of_device_id ast2600_espi_of_matches[] = { -+ { .compatible = "aspeed,ast2600-espi" }, -+ { }, -+}; ++ hdr = (struct espi_comm_hdr *)pkt; ++ hdr->cyc = d->cyc; ++ hdr->tag = d->tag; ++ hdr->len_h = d->len >> 8; ++ hdr->len_l = d->len & 0xff; ++ memcpy(hdr + 1, oob->dma.rx_virt + (PAGE_SIZE * wptr), pkt_len - sizeof(*hdr)); + -+static struct platform_driver ast2600_espi_driver = { -+ .driver = { -+ .name = "ast2600-espi", -+ .of_match_table = ast2600_espi_of_matches, -+ }, -+ .probe = ast2600_espi_probe, -+ .remove = ast2600_espi_remove, -+}; ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+module_platform_driver(ast2600_espi_driver); ++ spin_lock_irqsave(&oob->lock, flags); + -+MODULE_AUTHOR("Chia-Wei Wang "); -+MODULE_DESCRIPTION("Control of AST2600 eSPI Device"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2600-espi.h b/drivers/soc/aspeed/ast2600-espi.h ---- a/drivers/soc/aspeed/ast2600-espi.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2600-espi.h 2025-12-23 10:16:21.126032636 +0000 -@@ -0,0 +1,297 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#ifndef _AST2600_ESPI_H_ -+#define _AST2600_ESPI_H_ ++ /* make current descriptor available again */ ++ d->dirty = 0; + -+#include -+#include "aspeed-espi-comm.h" ++ wptr = ((wptr + 1) % OOB_DMA_DESC_NUM); ++ writel(wptr | ESPI_CH2_RX_DESC_WPTR_VALID, espi->regs + ESPI_CH2_RX_DESC_WPTR); + -+/* registers */ -+#define ESPI_CTRL 0x000 -+#define ESPI_CTRL_FLASH_TX_SW_RST BIT(31) -+#define ESPI_CTRL_FLASH_RX_SW_RST BIT(30) -+#define ESPI_CTRL_OOB_TX_SW_RST BIT(29) -+#define ESPI_CTRL_OOB_RX_SW_RST BIT(28) -+#define ESPI_CTRL_PERIF_NP_TX_SW_RST BIT(27) -+#define ESPI_CTRL_PERIF_NP_RX_SW_RST BIT(26) -+#define ESPI_CTRL_PERIF_PC_TX_SW_RST BIT(25) -+#define ESPI_CTRL_PERIF_PC_RX_SW_RST BIT(24) -+#define ESPI_CTRL_FLASH_TX_DMA_EN BIT(23) -+#define ESPI_CTRL_FLASH_RX_DMA_EN BIT(22) -+#define ESPI_CTRL_OOB_TX_DMA_EN BIT(21) -+#define ESPI_CTRL_OOB_RX_DMA_EN BIT(20) -+#define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) -+#define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) -+#define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) -+#define ESPI_CTRL_FLASH_SAFS_MODE GENMASK(11, 10) -+#define ESPI_CTRL_VW_GPIO_SW BIT(9) -+#define ESPI_CTRL_FLASH_SW_RDY BIT(7) -+#define ESPI_CTRL_OOB_SW_RDY BIT(4) -+#define ESPI_CTRL_VW_SW_RDY BIT(3) -+#define ESPI_CTRL_PERIF_SW_RDY BIT(1) -+#define ESPI_STS 0x004 -+#define ESPI_INT_STS 0x008 -+#define ESPI_INT_STS_RST_DEASSERT BIT(31) -+#define ESPI_INT_STS_OOB_RX_TMOUT BIT(23) -+#define ESPI_INT_STS_VW_SYSEVT1 BIT(22) -+#define ESPI_INT_STS_FLASH_TX_ERR BIT(21) -+#define ESPI_INT_STS_OOB_TX_ERR BIT(20) -+#define ESPI_INT_STS_FLASH_TX_ABT BIT(19) -+#define ESPI_INT_STS_OOB_TX_ABT BIT(18) -+#define ESPI_INT_STS_PERIF_NP_TX_ABT BIT(17) -+#define ESPI_INT_STS_PERIF_PC_TX_ABT BIT(16) -+#define ESPI_INT_STS_FLASH_RX_ABT BIT(15) -+#define ESPI_INT_STS_OOB_RX_ABT BIT(14) -+#define ESPI_INT_STS_PERIF_NP_RX_ABT BIT(13) -+#define ESPI_INT_STS_PERIF_PC_RX_ABT BIT(12) -+#define ESPI_INT_STS_PERIF_NP_TX_ERR BIT(11) -+#define ESPI_INT_STS_PERIF_PC_TX_ERR BIT(10) -+#define ESPI_INT_STS_VW_GPIO BIT(9) -+#define ESPI_INT_STS_VW_SYSEVT BIT(8) -+#define ESPI_INT_STS_FLASH_TX_CMPLT BIT(7) -+#define ESPI_INT_STS_FLASH_RX_CMPLT BIT(6) -+#define ESPI_INT_STS_OOB_TX_CMPLT BIT(5) -+#define ESPI_INT_STS_OOB_RX_CMPLT BIT(4) -+#define ESPI_INT_STS_PERIF_NP_TX_CMPLT BIT(3) -+#define ESPI_INT_STS_PERIF_PC_TX_CMPLT BIT(1) -+#define ESPI_INT_STS_PERIF_PC_RX_CMPLT BIT(0) -+#define ESPI_INT_EN 0x00c -+#define ESPI_INT_EN_RST_DEASSERT BIT(31) -+#define ESPI_INT_EN_OOB_RX_TMOUT BIT(23) -+#define ESPI_INT_EN_VW_SYSEVT1 BIT(22) -+#define ESPI_INT_EN_FLASH_TX_ERR BIT(21) -+#define ESPI_INT_EN_OOB_TX_ERR BIT(20) -+#define ESPI_INT_EN_FLASH_TX_ABT BIT(19) -+#define ESPI_INT_EN_OOB_TX_ABT BIT(18) -+#define ESPI_INT_EN_PERIF_NP_TX_ABT BIT(17) -+#define ESPI_INT_EN_PERIF_PC_TX_ABT BIT(16) -+#define ESPI_INT_EN_FLASH_RX_ABT BIT(15) -+#define ESPI_INT_EN_OOB_RX_ABT BIT(14) -+#define ESPI_INT_EN_PERIF_NP_RX_ABT BIT(13) -+#define ESPI_INT_EN_PERIF_PC_RX_ABT BIT(12) -+#define ESPI_INT_EN_PERIF_NP_TX_ERR BIT(11) -+#define ESPI_INT_EN_PERIF_PC_TX_ERR BIT(10) -+#define ESPI_INT_EN_VW_GPIO BIT(9) -+#define ESPI_INT_EN_VW_SYSEVT BIT(8) -+#define ESPI_INT_EN_FLASH_TX_CMPLT BIT(7) -+#define ESPI_INT_EN_FLASH_RX_CMPLT BIT(6) -+#define ESPI_INT_EN_OOB_TX_CMPLT BIT(5) -+#define ESPI_INT_EN_OOB_RX_CMPLT BIT(4) -+#define ESPI_INT_EN_PERIF_NP_TX_CMPLT BIT(3) -+#define ESPI_INT_EN_PERIF_PC_TX_CMPLT BIT(1) -+#define ESPI_INT_EN_PERIF_PC_RX_CMPLT BIT(0) -+#define ESPI_PERIF_PC_RX_DMA 0x010 -+#define ESPI_PERIF_PC_RX_CTRL 0x014 -+#define ESPI_PERIF_PC_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_PERIF_PC_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_PERIF_PC_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_PERIF_PC_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_PERIF_PC_RX_DATA 0x018 -+#define ESPI_PERIF_PC_TX_DMA 0x020 -+#define ESPI_PERIF_PC_TX_CTRL 0x024 -+#define ESPI_PERIF_PC_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_PERIF_PC_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_PERIF_PC_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_PERIF_PC_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_PERIF_PC_TX_DATA 0x028 -+#define ESPI_PERIF_NP_TX_DMA 0x030 -+#define ESPI_PERIF_NP_TX_CTRL 0x034 -+#define ESPI_PERIF_NP_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_PERIF_NP_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_PERIF_NP_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_PERIF_NP_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_PERIF_NP_TX_DATA 0x038 -+#define ESPI_OOB_RX_DMA 0x040 -+#define ESPI_OOB_RX_CTRL 0x044 -+#define ESPI_OOB_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_OOB_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_OOB_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_OOB_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_OOB_RX_DATA 0x048 -+#define ESPI_OOB_TX_DMA 0x050 -+#define ESPI_OOB_TX_CTRL 0x054 -+#define ESPI_OOB_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_OOB_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_OOB_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_OOB_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_OOB_TX_DATA 0x058 -+#define ESPI_FLASH_RX_DMA 0x060 -+#define ESPI_FLASH_RX_CTRL 0x064 -+#define ESPI_FLASH_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_FLASH_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_FLASH_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_FLASH_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_FLASH_RX_DATA 0x068 -+#define ESPI_FLASH_TX_DMA 0x070 -+#define ESPI_FLASH_TX_CTRL 0x074 -+#define ESPI_FLASH_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_FLASH_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_FLASH_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_FLASH_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_FLASH_TX_DATA 0x078 -+#define ESPI_CTRL2 0x080 -+#define ESPI_CTRL2_VW_TX_SORT BIT(30) -+#define ESPI_CTRL2_MCYC_RD_DIS_WDT BIT(11) -+#define ESPI_CTRL2_MCYC_WR_DIS_WDT BIT(10) -+#define ESPI_CTRL2_MCYC_RD_DIS BIT(6) -+#define ESPI_CTRL2_MMBI_RD_DIS ESPI_CTRL2_MCYC_RD_DIS -+#define ESPI_CTRL2_MCYC_WR_DIS BIT(4) -+#define ESPI_CTRL2_MMBI_WR_DIS ESPI_CTRL2_MCYC_WR_DIS -+#define ESPI_PERIF_MCYC_SADDR 0x084 -+#define ESPI_PERIF_MMBI_SADDR ESPI_PERIF_MCYC_SADDR -+#define ESPI_PERIF_MCYC_TADDR 0x088 -+#define ESPI_PERIF_MMBI_TADDR ESPI_PERIF_MCYC_TADDR -+#define ESPI_PERIF_MCYC_MASK 0x08c -+#define ESPI_PERIF_MMBI_MASK ESPI_PERIF_MCYC_MASK -+#define ESPI_FLASH_SAFS_TADDR 0x090 -+#define ESPI_FLASH_SAFS_TADDR_BASE GENMASK(31, 24) -+#define ESPI_FLASH_SAFS_TADDR_MASK GENMASK(15, 8) -+#define ESPI_VW_SYSEVT_INT_EN 0x094 -+#define ESPI_VW_SYSEVT 0x098 -+#define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) -+#define ESPI_VW_SYSEVT_RST_CPU_INIT BIT(26) -+#define ESPI_VW_SYSEVT_SLV_BOOT_STS BIT(23) -+#define ESPI_VW_SYSEVT_NON_FATAL_ERR BIT(22) -+#define ESPI_VW_SYSEVT_FATAL_ERR BIT(21) -+#define ESPI_VW_SYSEVT_SLV_BOOT_DONE BIT(20) -+#define ESPI_VW_SYSEVT_OOB_RST_ACK BIT(16) -+#define ESPI_VW_SYSEVT_NMI_OUT BIT(10) -+#define ESPI_VW_SYSEVT_SMI_OUT BIT(9) -+#define ESPI_VW_SYSEVT_HOST_RST_WARN BIT(8) -+#define ESPI_VW_SYSEVT_OOB_RST_WARN BIT(6) -+#define ESPI_VW_SYSEVT_PLTRSTN BIT(5) -+#define ESPI_VW_SYSEVT_SUSPEND BIT(4) -+#define ESPI_VW_SYSEVT_S5_SLEEP BIT(2) -+#define ESPI_VW_SYSEVT_S4_SLEEP BIT(1) -+#define ESPI_VW_SYSEVT_S3_SLEEP BIT(0) -+#define ESPI_VW_GPIO_VAL 0x09c -+#define ESPI_GEN_CAP_N_CONF 0x0a0 -+#define ESPI_CH0_CAP_N_CONF 0x0a4 -+#define ESPI_CH1_CAP_N_CONF 0x0a8 -+#define ESPI_CH2_CAP_N_CONF 0x0ac -+#define ESPI_CH3_CAP_N_CONF 0x0b0 -+#define ESPI_CH3_CAP_N_CONF2 0x0b4 -+#define ESPI_VW_GPIO_DIR 0x0c0 -+#define ESPI_VW_GPIO_GRP 0x0c4 -+#define ESPI_INT_EN_CLR 0x0fc -+#define ESPI_VW_SYSEVT1_INT_EN 0x100 -+#define ESPI_VW_SYSEVT1 0x104 -+#define ESPI_VW_SYSEVT1_SUSPEND_ACK BIT(20) -+#define ESPI_VW_SYSEVT1_SUSPEND_WARN BIT(0) -+#define ESPI_VW_SYSEVT_INT_T0 0x110 -+#define ESPI_VW_SYSEVT_INT_T1 0x114 -+#define ESPI_VW_SYSEVT_INT_T2 0x118 -+#define ESPI_VW_SYSEVT_INT_STS 0x11c -+#define ESPI_VW_SYSEVT1_INT_T0 0x120 -+#define ESPI_VW_SYSEVT1_INT_T1 0x124 -+#define ESPI_VW_SYSEVT1_INT_T2 0x128 -+#define ESPI_VW_SYSEVT1_INT_STS 0x12c -+#define ESPI_OOB_RX_DESC_NUM 0x130 -+#define ESPI_OOB_RX_DESC_RPTR 0x134 -+#define ESPI_OOB_RX_DESC_RPTR_UPDATE BIT(31) -+#define ESPI_OOB_RX_DESC_RPTR_RP GENMASK(11, 0) -+#define ESPI_OOB_RX_DESC_WPTR 0x138 -+#define ESPI_OOB_RX_DESC_WPTR_RECV_EN BIT(31) -+#define ESPI_OOB_RX_DESC_WPTR_SP GENMASK(27, 16) -+#define ESPI_OOB_RX_DESC_WPTR_WP GENMASK(11, 0) -+#define ESPI_OOB_TX_DESC_NUM 0x140 -+#define ESPI_OOB_TX_DESC_RPTR 0x144 -+#define ESPI_OOB_TX_DESC_RPTR_UPDATE BIT(31) -+#define ESPI_OOB_TX_DESC_WPTR 0x148 -+#define ESPI_OOB_TX_DESC_WPTR_SEND_EN BIT(31) -+#define ESPI_MMBI_CTRL 0x800 -+#define ESPI_MMBI_CTRL_INST_SZ GENMASK(10, 8) -+#define ESPI_MMBI_CTRL_TOTAL_SZ GENMASK(6, 4) -+#define ESPI_MMBI_CTRL_EN BIT(0) -+#define ESPI_MMBI_INT_STS 0x808 -+#define ESPI_MMBI_INT_EN 0x80c -+#define ESPI_MMBI_HOST_RWP(x) (0x810 + ((x) << 3)) ++ /* set ready flag base on the next RX descriptor */ ++ oob->rx_ready = rx_descs[wptr].dirty; + -+/* collect ESPI_INT_EN bits for convenience */ -+#define ESPI_INT_EN_PERIF \ -+ (ESPI_INT_EN_PERIF_NP_TX_ABT | \ -+ ESPI_INT_EN_PERIF_PC_TX_ABT | \ -+ ESPI_INT_EN_PERIF_NP_RX_ABT | \ -+ ESPI_INT_EN_PERIF_PC_RX_ABT | \ -+ ESPI_INT_EN_PERIF_NP_TX_ERR | \ -+ ESPI_INT_EN_PERIF_PC_TX_ERR | \ -+ ESPI_INT_EN_PERIF_NP_TX_CMPLT | \ -+ ESPI_INT_EN_PERIF_PC_TX_CMPLT | \ -+ ESPI_INT_EN_PERIF_PC_RX_CMPLT) ++ spin_unlock_irqrestore(&oob->lock, flags); + -+#define ESPI_INT_EN_VW \ -+ (ESPI_INT_EN_VW_SYSEVT1 | \ -+ ESPI_INT_EN_VW_GPIO | \ -+ ESPI_INT_EN_VW_SYSEVT) ++ rc = 0; + -+#define ESPI_INT_EN_OOB \ -+ (ESPI_INT_EN_OOB_RX_TMOUT | \ -+ ESPI_INT_EN_OOB_TX_ERR | \ -+ ESPI_INT_EN_OOB_TX_ABT | \ -+ ESPI_INT_EN_OOB_RX_ABT | \ -+ ESPI_INT_EN_OOB_TX_CMPLT | \ -+ ESPI_INT_EN_OOB_RX_CMPLT) ++free_n_out: ++ vfree(pkt); + -+#define ESPI_INT_EN_FLASH \ -+ (ESPI_INT_EN_FLASH_TX_ERR | \ -+ ESPI_INT_EN_FLASH_TX_ABT | \ -+ ESPI_INT_EN_FLASH_RX_ABT | \ -+ ESPI_INT_EN_FLASH_TX_CMPLT | \ -+ ESPI_INT_EN_FLASH_RX_CMPLT) ++ return rc; ++} + -+/* collect ESPI_INT_STS bits for convenience */ -+#define ESPI_INT_STS_PERIF \ -+ (ESPI_INT_STS_PERIF_NP_TX_ABT | \ -+ ESPI_INT_STS_PERIF_PC_TX_ABT | \ -+ ESPI_INT_STS_PERIF_NP_RX_ABT | \ -+ ESPI_INT_STS_PERIF_PC_RX_ABT | \ -+ ESPI_INT_STS_PERIF_NP_TX_ERR | \ -+ ESPI_INT_STS_PERIF_PC_TX_ERR | \ -+ ESPI_INT_STS_PERIF_NP_TX_CMPLT | \ -+ ESPI_INT_STS_PERIF_PC_TX_CMPLT | \ -+ ESPI_INT_STS_PERIF_PC_RX_CMPLT) ++static long ast2700_espi_oob_get_rx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ unsigned long flags; ++ u32 pkt_len; ++ u8 *pkt; ++ int i, rc; + -+#define ESPI_INT_STS_VW \ -+ (ESPI_INT_STS_VW_SYSEVT1 | \ -+ ESPI_INT_STS_VW_GPIO | \ -+ ESPI_INT_STS_VW_SYSEVT) ++ espi = container_of(oob, struct aspeed_espi, oob); + -+#define ESPI_INT_STS_OOB \ -+ (ESPI_INT_STS_OOB_RX_TMOUT | \ -+ ESPI_INT_STS_OOB_TX_ERR | \ -+ ESPI_INT_STS_OOB_TX_ABT | \ -+ ESPI_INT_STS_OOB_RX_ABT | \ -+ ESPI_INT_STS_OOB_TX_CMPLT | \ -+ ESPI_INT_STS_OOB_RX_CMPLT) ++ if (fp->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&oob->rx_mtx)) ++ return -EAGAIN; + -+#define ESPI_INT_STS_FLASH \ -+ (ESPI_INT_STS_FLASH_TX_ERR | \ -+ ESPI_INT_STS_FLASH_TX_ABT | \ -+ ESPI_INT_STS_FLASH_RX_ABT | \ -+ ESPI_INT_STS_FLASH_TX_CMPLT | \ -+ ESPI_INT_STS_FLASH_RX_CMPLT) ++ if (!oob->rx_ready) { ++ rc = -ENODATA; ++ goto unlock_mtx_n_out; ++ } ++ } else { ++ mutex_lock(&oob->rx_mtx); + -+/* consistent with DTS property "flash-safs-mode" */ -+enum ast2600_safs_mode { -+ SAFS_MODE_MIX = 0x0, -+ SAFS_MODE_SW, -+ SAFS_MODE_HW, -+ SAFS_MODES, -+}; ++ if (!oob->rx_ready) { ++ rc = wait_event_interruptible(oob->wq, oob->rx_ready); ++ if (rc == -ERESTARTSYS) { ++ rc = -EINTR; ++ goto unlock_mtx_n_out; ++ } ++ } ++ } + -+/* consistent with DTS property "perif-mmbi-instance-size" */ -+enum ast2600_mmbi_instance_size { -+ MMBI_INST_SIZE_8KB = 0x0, -+ MMBI_INST_SIZE_16KB, -+ MMBI_INST_SIZE_32KB, -+ MMBI_INST_SIZE_64KB, -+ MMBI_INST_SIZE_128KB, -+ MMBI_INST_SIZE_256KB, -+ MMBI_INST_SIZE_512KB, -+ MMBI_INST_SIZE_1024KB, -+ MMBI_INST_SIZE_TYPES, -+}; ++ if (oob->dma.enable) { ++ rc = ast2700_espi_oob_dma_get_rx(fp, oob, ioc); ++ goto unlock_mtx_n_out; ++ } + -+#endif -diff --git a/drivers/soc/aspeed/ast2600-otp.c b/drivers/soc/aspeed/ast2600-otp.c ---- a/drivers/soc/aspeed/ast2600-otp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2600-otp.c 2025-12-23 10:16:21.126032636 +0000 -@@ -0,0 +1,638 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) ASPEED Technology Inc. -+ */ ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ reg = readl(espi->regs + ESPI_CH2_RX_CTRL); ++ cyc = FIELD_GET(ESPI_CH2_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_CH2_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_CH2_RX_CTRL_LEN, reg); + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ /* ++ * calculate the length of the rest part of the ++ * eSPI packet to be read from HW and copied to ++ * user space. ++ */ ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); + -+#define ASPEED_REVISION_ID0 0x04 -+#define ASPEED_REVISION_ID1 0x14 -+#define ID0_AST2600A0 0x05000303 -+#define ID1_AST2600A0 0x05000303 -+#define ID0_AST2600A1 0x05010303 -+#define ID1_AST2600A1 0x05010303 -+#define ID0_AST2600A2 0x05010303 -+#define ID1_AST2600A2 0x05020303 -+#define ID0_AST2600A3 0x05030303 -+#define ID1_AST2600A3 0x05030303 -+#define ID0_AST2620A1 0x05010203 -+#define ID1_AST2620A1 0x05010203 -+#define ID0_AST2620A2 0x05010203 -+#define ID1_AST2620A2 0x05020203 -+#define ID0_AST2620A3 0x05030203 -+#define ID1_AST2620A3 0x05030203 -+#define ID0_AST2605A2 0x05010103 -+#define ID1_AST2605A2 0x05020103 -+#define ID0_AST2605A3 0x05030103 -+#define ID1_AST2605A3 0x05030103 -+#define ID0_AST2625A3 0x05030403 -+#define ID1_AST2625A3 0x05030403 ++ if (ioc->pkt_len < pkt_len) { ++ rc = -EINVAL; ++ goto unlock_mtx_n_out; ++ } ++ ++ pkt = vmalloc(pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; ++ } + -+#define OTP_PROTECT_KEY 0x0 -+#define OTP_PASSWD 0x349fe38a -+#define OTP_COMMAND 0x4 -+#define OTP_TIMING 0x8 -+#define OTP_ADDR 0x10 -+#define OTP_STATUS 0x14 -+#define OTP_COMPARE_1 0x20 -+#define OTP_COMPARE_2 0x24 -+#define OTP_COMPARE_3 0x28 -+#define OTP_COMPARE_4 0x2c -+#define SW_REV_ID0 0x68 -+#define SW_REV_ID1 0x6c -+#define SEC_KEY_NUM 0x78 -+#define RETRY 20 ++ hdr = (struct espi_comm_hdr *)pkt; ++ hdr->cyc = cyc; ++ hdr->tag = tag; ++ hdr->len_h = len >> 8; ++ hdr->len_l = len & 0xff; + -+struct aspeed_otp { -+ struct miscdevice miscdev; -+ void __iomem *reg_base; -+ bool is_open; -+ u32 otp_ver; -+ u32 *data; -+}; ++ for (i = sizeof(*hdr); i < pkt_len; ++i) { ++ reg = readl(espi->regs + ESPI_CH2_RX_DATA); ++ pkt[i] = reg & 0xff; ++ } + -+static DEFINE_SPINLOCK(otp_state_lock); ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+static inline u32 aspeed_otp_read(struct aspeed_otp *ctx, u32 reg) -+{ -+ int val; ++ spin_lock_irqsave(&oob->lock, flags); + -+ val = readl(ctx->reg_base + reg); -+ // printk("read:reg = 0x%08x, val = 0x%08x\n", reg, val); -+ return val; -+} ++ writel(ESPI_CH2_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH2_RX_CTRL); ++ oob->rx_ready = 0; + -+static inline void aspeed_otp_write(struct aspeed_otp *ctx, u32 val, u32 reg) -+{ -+ // printk("write:reg = 0x%08x, val = 0x%08x\n", reg, val); -+ writel(val, ctx->reg_base + reg); -+} ++ spin_unlock_irqrestore(&oob->lock, flags); + -+static uint32_t chip_version(u32 revid0, u32 revid1) -+{ -+ if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { -+ /* AST2600-A0 */ -+ return OTP_A0; -+ } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { -+ /* AST2600-A1 */ -+ return OTP_A1; -+ } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { -+ /* AST2600-A2 */ -+ return OTP_A2; -+ } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { -+ /* AST2600-A3 */ -+ return OTP_A3; -+ } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { -+ /* AST2620-A1 */ -+ return OTP_A1; -+ } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { -+ /* AST2620-A2 */ -+ return OTP_A2; -+ } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { -+ /* AST2620-A3 */ -+ return OTP_A3; -+ } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { -+ /* AST2605-A2 */ -+ return OTP_A2; -+ } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { -+ /* AST2605-A3 */ -+ return OTP_A3; -+ } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { -+ /* AST2605-A3 */ -+ return OTP_A3; -+ } -+ return -1; -+} ++ rc = 0; + -+static void wait_complete(struct aspeed_otp *ctx) -+{ -+ int reg; -+ int i = 0; ++free_n_out: ++ vfree(pkt); + -+ do { -+ reg = aspeed_otp_read(ctx, OTP_STATUS); -+ if ((reg & 0x6) == 0x6) -+ i++; -+ } while (i != 2); -+} ++unlock_mtx_n_out: ++ mutex_unlock(&oob->rx_mtx); + -+static void otp_write(struct aspeed_otp *ctx, u32 otp_addr, u32 val) -+{ -+ aspeed_otp_write(ctx, otp_addr, OTP_ADDR); //write address -+ aspeed_otp_write(ctx, val, OTP_COMPARE_1); //write val -+ aspeed_otp_write(ctx, 0x23b1e362, OTP_COMMAND); //write command -+ wait_complete(ctx); ++ return rc; +} + -+static void otp_soak(struct aspeed_otp *ctx, int soak) ++static long ast2700_espi_oob_dma_put_tx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) +{ -+ if (ctx->otp_ver == OTP_A2 || ctx->otp_ver == OTP_A3) { -+ switch (soak) { -+ case 0: //default -+ otp_write(ctx, 0x3000, 0x0); // Write MRA -+ otp_write(ctx, 0x5000, 0x0); // Write MRB -+ otp_write(ctx, 0x1000, 0x0); // Write MR -+ break; -+ case 1: //normal program -+ otp_write(ctx, 0x3000, 0x1320); // Write MRA -+ otp_write(ctx, 0x5000, 0x1008); // Write MRB -+ otp_write(ctx, 0x1000, 0x0024); // Write MR -+ aspeed_otp_write(ctx, 0x04191388, OTP_TIMING); // 200us -+ break; -+ case 2: //soak program -+ otp_write(ctx, 0x3000, 0x1320); // Write MRA -+ otp_write(ctx, 0x5000, 0x0007); // Write MRB -+ otp_write(ctx, 0x1000, 0x0100); // Write MR -+ aspeed_otp_write(ctx, 0x04193a98, OTP_TIMING); // 600us -+ break; -+ } -+ } else { -+ switch (soak) { -+ case 0: //default -+ otp_write(ctx, 0x3000, 0x0); // Write MRA -+ otp_write(ctx, 0x5000, 0x0); // Write MRB -+ otp_write(ctx, 0x1000, 0x0); // Write MR -+ break; -+ case 1: //normal program -+ otp_write(ctx, 0x3000, 0x4021); // Write MRA -+ otp_write(ctx, 0x5000, 0x302f); // Write MRB -+ otp_write(ctx, 0x1000, 0x4020); // Write MR -+ aspeed_otp_write(ctx, 0x04190760, OTP_TIMING); // 75us -+ break; -+ case 2: //soak program -+ otp_write(ctx, 0x3000, 0x4021); // Write MRA -+ otp_write(ctx, 0x5000, 0x1027); // Write MRB -+ otp_write(ctx, 0x1000, 0x4820); // Write MR -+ aspeed_otp_write(ctx, 0x041930d4, OTP_TIMING); // 500us -+ break; -+ } -+ } ++ struct ast2700_espi_oob_dma_tx_desc *d; ++ struct ast2700_espi_oob_dma_tx_desc *tx_descs; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u32 rptr, wptr; ++ u8 *pkt; ++ int rc; + -+ wait_complete(ctx); -+} ++ espi = container_of(oob, struct aspeed_espi, oob); + -+static int verify_bit(struct aspeed_otp *ctx, u32 otp_addr, int bit_offset, int value) -+{ -+ u32 ret[2]; ++ pkt = vzalloc(ioc->pkt_len); ++ if (!pkt) ++ return -ENOMEM; + -+ if (otp_addr % 2 == 0) -+ aspeed_otp_write(ctx, otp_addr, OTP_ADDR); //Read address -+ else -+ aspeed_otp_write(ctx, otp_addr - 1, OTP_ADDR); //Read address ++ hdr = (struct espi_comm_hdr *)pkt; + -+ aspeed_otp_write(ctx, 0x23b1e361, OTP_COMMAND); //trigger read -+ wait_complete(ctx); -+ ret[0] = aspeed_otp_read(ctx, OTP_COMPARE_1); -+ ret[1] = aspeed_otp_read(ctx, OTP_COMPARE_2); ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+ if (otp_addr % 2 == 0) { -+ if (((ret[0] >> bit_offset) & 1) == value) -+ return 0; -+ else -+ return -1; -+ } else { -+ if (((ret[1] >> bit_offset) & 1) == value) -+ return 0; -+ else -+ return -1; ++ /* kick HW to update descriptor read/write pointer */ ++ writel(ESPI_CH2_TX_DESC_RPTR_UPT, espi->regs + ESPI_CH2_TX_DESC_RPTR); ++ ++ rptr = readl(espi->regs + ESPI_CH2_TX_DESC_RPTR); ++ wptr = readl(espi->regs + ESPI_CH2_TX_DESC_WPTR); ++ ++ if (((wptr + 1) % OOB_DMA_DESC_NUM) == rptr) { ++ rc = -EBUSY; ++ goto free_n_out; + } -+} + -+static void otp_prog(struct aspeed_otp *ctx, u32 otp_addr, u32 prog_bit) -+{ -+ otp_write(ctx, 0x0, prog_bit); -+ aspeed_otp_write(ctx, otp_addr, OTP_ADDR); //write address -+ aspeed_otp_write(ctx, prog_bit, OTP_COMPARE_1); //write data -+ aspeed_otp_write(ctx, 0x23b1e364, OTP_COMMAND); //write command -+ wait_complete(ctx); ++ tx_descs = (struct ast2700_espi_oob_dma_tx_desc *)oob->dma.txd_virt; ++ d = &tx_descs[wptr]; ++ d->cyc = hdr->cyc; ++ d->tag = hdr->tag; ++ d->len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ d->msg_type = OOB_DMA_DESC_CUSTOM; ++ ++ memcpy(oob->dma.tx_virt + (PAGE_SIZE * wptr), hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ ++ dma_wmb(); ++ ++ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; ++ writel(wptr | ESPI_CH2_TX_DESC_WPTR_VALID, espi->regs + ESPI_CH2_TX_DESC_WPTR); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++ return rc; +} + -+static void _otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) ++static long ast2700_espi_oob_put_tx(struct file *fp, ++ struct aspeed_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) +{ -+ int prog_bit; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u8 *pkt; ++ int i, rc; + -+ if (prog_address % 2 == 0) { -+ if (value) -+ prog_bit = ~(0x1 << bit_offset); -+ else -+ return; -+ } else { -+ if (ctx->otp_ver != OTP_A3) -+ prog_address |= 1 << 15; -+ if (!value) -+ prog_bit = 0x1 << bit_offset; -+ else -+ return; ++ espi = container_of(oob, struct aspeed_espi, oob); ++ ++ if (!mutex_trylock(&oob->tx_mtx)) ++ return -EAGAIN; ++ ++ if (oob->dma.enable) { ++ rc = ast2700_espi_oob_dma_put_tx(fp, oob, ioc); ++ goto unlock_mtx_n_out; + } -+ otp_prog(ctx, prog_address, prog_bit); -+} + -+static int otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) -+{ -+ int pass; -+ int i; ++ reg = readl(espi->regs + ESPI_CH2_TX_CTRL); ++ if (reg & ESPI_CH2_TX_CTRL_TRIG_PEND) { ++ rc = -EBUSY; ++ goto unlock_mtx_n_out; ++ } + -+ otp_soak(ctx, 1); -+ _otp_prog_bit(ctx, value, prog_address, bit_offset); -+ pass = 0; ++ if (ioc->pkt_len > ESPI_MAX_PKT_LEN) { ++ rc = -EINVAL; ++ goto unlock_mtx_n_out; ++ } + -+ for (i = 0; i < RETRY; i++) { -+ if (verify_bit(ctx, prog_address, bit_offset, value) != 0) { -+ otp_soak(ctx, 2); -+ _otp_prog_bit(ctx, value, prog_address, bit_offset); -+ if (verify_bit(ctx, prog_address, bit_offset, value) != 0) { -+ otp_soak(ctx, 1); -+ } else { -+ pass = 1; -+ break; -+ } -+ } else { -+ pass = 1; -+ break; -+ } ++ pkt = vmalloc(ioc->pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; + } -+ otp_soak(ctx, 0); -+ return pass; -+} + -+static void otp_read_conf_dw(struct aspeed_otp *ctx, u32 offset, u32 *buf) -+{ -+ u32 config_offset; ++ hdr = (struct espi_comm_hdr *)pkt; + -+ config_offset = 0x800; -+ config_offset |= (offset / 8) * 0x200; -+ config_offset |= (offset % 8) * 0x2; ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+ aspeed_otp_write(ctx, config_offset, OTP_ADDR); //Read address -+ aspeed_otp_write(ctx, 0x23b1e361, OTP_COMMAND); //trigger read -+ wait_complete(ctx); -+ buf[0] = aspeed_otp_read(ctx, OTP_COMPARE_1); -+} ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) ++ writel(pkt[i], espi->regs + ESPI_CH2_TX_DATA); + -+static void otp_read_conf(struct aspeed_otp *ctx, u32 offset, u32 len) -+{ -+ int i, j; ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ otp_soak(ctx, 0); -+ for (i = offset, j = 0; j < len; i++, j++) -+ otp_read_conf_dw(ctx, i, &ctx->data[j]); ++ reg = FIELD_PREP(ESPI_CH2_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_CH2_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_CH2_TX_CTRL_LEN, len) ++ | ESPI_CH2_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_CH2_TX_CTRL); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++unlock_mtx_n_out: ++ mutex_unlock(&oob->tx_mtx); ++ ++ return rc; +} + -+static void otp_read_data_2dw(struct aspeed_otp *ctx, u32 offset, u32 *buf) ++static long ast2700_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ aspeed_otp_write(ctx, offset, OTP_ADDR); //Read address -+ aspeed_otp_write(ctx, 0x23b1e361, OTP_COMMAND); //trigger read -+ wait_complete(ctx); -+ buf[0] = aspeed_otp_read(ctx, OTP_COMPARE_1); -+ buf[1] = aspeed_otp_read(ctx, OTP_COMPARE_2); ++ struct aspeed_espi_oob *oob; ++ struct aspeed_espi_ioc ioc; ++ ++ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); ++ ++ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) ++ return -EFAULT; ++ ++ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case ASPEED_ESPI_OOB_GET_RX: ++ return ast2700_espi_oob_get_rx(fp, oob, &ioc); ++ case ASPEED_ESPI_OOB_PUT_TX: ++ return ast2700_espi_oob_put_tx(fp, oob, &ioc); ++ }; ++ ++ return -EINVAL; +} + -+static void otp_read_data(struct aspeed_otp *ctx, u32 offset, u32 len) ++static const struct file_operations ast2700_espi_oob_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2700_espi_oob_ioctl, ++}; ++ ++static void ast2700_espi_oob_isr(struct aspeed_espi *espi) +{ -+ int i, j; -+ u32 ret[2]; ++ struct aspeed_espi_oob *oob; ++ unsigned long flags; ++ u32 sts; + -+ otp_soak(ctx, 0); ++ oob = &espi->oob; + -+ i = offset; -+ j = 0; -+ if (offset % 2) { -+ otp_read_data_2dw(ctx, i - 1, ret); -+ ctx->data[0] = ret[1]; -+ i++; -+ j++; ++ sts = readl(espi->regs + ESPI_CH2_INT_STS); ++ ++ if (sts & ESPI_CH2_INT_STS_RX_CMPLT) { ++ writel(ESPI_CH2_INT_STS_RX_CMPLT, espi->regs + ESPI_CH2_INT_STS); ++ ++ spin_lock_irqsave(&oob->lock, flags); ++ oob->rx_ready = true; ++ spin_unlock_irqrestore(&oob->lock, flags); ++ ++ wake_up_interruptible(&oob->wq); + } -+ for (; j < len; i += 2, j += 2) -+ otp_read_data_2dw(ctx, i, &ctx->data[j]); +} + -+static int otp_prog_data(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) ++static void ast2700_espi_oob_reset(struct aspeed_espi *espi) +{ -+ u32 read[2]; -+ int otp_bit; ++ struct aspeed_espi_oob *oob; ++ struct ast2700_espi_oob_dma_tx_desc *tx_desc; ++ struct ast2700_espi_oob_dma_rx_desc *rx_desc; ++ dma_addr_t tx_addr, rx_addr; ++ u32 reg; ++ int i; + -+ if (dw_offset % 2 == 0) { -+ otp_read_data_2dw(ctx, dw_offset, read); -+ otp_bit = (read[0] >> bit_offset) & 0x1; ++ oob = &espi->oob; + -+ if (otp_bit == 1 && value == 0) { -+ pr_err("OTPDATA%X[%X] = 1\n", dw_offset, bit_offset); -+ pr_err("OTP is programed, which can't be cleaned\n"); -+ return -EINVAL; -+ } -+ } else { -+ otp_read_data_2dw(ctx, dw_offset - 1, read); -+ otp_bit = (read[1] >> bit_offset) & 0x1; ++ writel(0x0, espi->regs + ESPI_CH2_INT_EN); ++ writel(0xffffffff, espi->regs + ESPI_CH2_INT_STS); + -+ if (otp_bit == 0 && value == 1) { -+ pr_err("OTPDATA%X[%X] = 1\n", dw_offset, bit_offset); -+ pr_err("OTP is programed, which can't be writen\n"); -+ return -EINVAL; ++ reg = readl(espi->regs + ESPI_CH2_CTRL); ++ reg &= ~(ESPI_CH2_CTRL_TX_RST ++ | ESPI_CH2_CTRL_RX_RST ++ | ESPI_CH2_CTRL_TX_DMA_EN ++ | ESPI_CH2_CTRL_RX_DMA_EN ++ | ESPI_CH2_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ ++ udelay(1); ++ ++ reg |= (ESPI_CH2_CTRL_TX_RST | ESPI_CH2_CTRL_RX_RST); ++ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ ++ if (oob->dma.enable) { ++ tx_addr = oob->dma.tx_addr; ++ rx_addr = oob->dma.rx_addr; ++ ++ tx_desc = (struct ast2700_espi_oob_dma_tx_desc *)oob->dma.txd_virt; ++ rx_desc = (struct ast2700_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; ++ ++ for (i = 0; i < OOB_DMA_DESC_NUM; ++i) { ++ tx_desc[i].data_addrh = upper_32_bits(tx_addr); ++ tx_desc[i].data_addrl = tx_addr & 0xffffffff; ++ tx_addr += PAGE_SIZE; ++ ++ rx_desc[i].data_addrh = upper_32_bits(rx_addr); ++ rx_desc[i].data_addrl = rx_addr & 0xffffffff; ++ rx_desc[i].dirty = 0; ++ rx_addr += PAGE_SIZE; + } -+ } -+ if (otp_bit == value) { -+ pr_err("OTPDATA%X[%X] = %d\n", dw_offset, bit_offset, value); -+ pr_err("No need to program\n"); -+ return 0; ++ ++ writel(upper_32_bits(oob->dma.txd_addr), espi->regs + ESPI_CH2_TX_DMAH); ++ writel(oob->dma.txd_addr & 0xffffffff, espi->regs + ESPI_CH2_TX_DMAL); ++ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_CH2_TX_DESC_RPTR); ++ writel(0x0, espi->regs + ESPI_CH2_TX_DESC_WPTR); ++ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_CH2_TX_DESC_EPTR); ++ ++ writel(upper_32_bits(oob->dma.rxd_addr), espi->regs + ESPI_CH2_RX_DMAH); ++ writel(oob->dma.rxd_addr & 0xffffffff, espi->regs + ESPI_CH2_RX_DMAL); ++ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_CH2_RX_DESC_RPTR); ++ writel(0x0, espi->regs + ESPI_CH2_RX_DESC_WPTR); ++ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_CH2_RX_DESC_EPTR); ++ ++ reg = readl(espi->regs + ESPI_CH2_CTRL) ++ | ESPI_CH2_CTRL_TX_DMA_EN ++ | ESPI_CH2_CTRL_RX_DMA_EN; ++ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ ++ /* activate RX DMA to make OOB_FREE */ ++ reg = readl(espi->regs + ESPI_CH2_RX_DESC_WPTR) | ESPI_CH2_RX_DESC_WPTR_VALID; ++ writel(reg, espi->regs + ESPI_CH2_RX_DESC_WPTR); + } + -+ return otp_prog_bit(ctx, value, dw_offset, bit_offset); ++ writel(ESPI_CH2_INT_EN_RX_CMPLT, espi->regs + ESPI_CH2_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CH2_CTRL) | ESPI_CH2_CTRL_SW_RDY; ++ writel(reg, espi->regs + ESPI_CH2_CTRL); +} + -+static int otp_prog_conf(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) ++int ast2700_espi_oob_probe(struct aspeed_espi *espi) +{ -+ u32 read; -+ u32 prog_address = 0; -+ int otp_bit; ++ struct aspeed_espi_oob *oob; ++ struct device *dev; ++ int rc; + -+ otp_read_conf_dw(ctx, dw_offset, &read); ++ dev = espi->dev; + -+ prog_address = 0x800; -+ prog_address |= (dw_offset / 8) * 0x200; -+ prog_address |= (dw_offset % 8) * 0x2; -+ otp_bit = (read >> bit_offset) & 0x1; -+ if (otp_bit == value) { -+ pr_err("OTPCFG%X[%X] = %d\n", dw_offset, bit_offset, value); -+ pr_err("No need to program\n"); -+ return 0; -+ } -+ if (otp_bit == 1 && value == 0) { -+ pr_err("OTPCFG%X[%X] = 1\n", dw_offset, bit_offset); -+ pr_err("OTP is programed, which can't be clean\n"); -+ return -EINVAL; ++ oob = &espi->oob; ++ ++ init_waitqueue_head(&oob->wq); ++ ++ spin_lock_init(&oob->lock); ++ ++ mutex_init(&oob->tx_mtx); ++ mutex_init(&oob->rx_mtx); ++ ++ oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); ++ if (oob->dma.enable) { ++ oob->dma.txd_virt = dmam_alloc_coherent(dev, ++ sizeof(struct ast2700_espi_oob_dma_tx_desc) * ++ OOB_DMA_DESC_NUM, ++ &oob->dma.txd_addr, GFP_KERNEL); ++ if (!oob->dma.txd_virt) { ++ dev_err(dev, "cannot allocate DMA TX descriptor\n"); ++ return -ENOMEM; ++ } ++ oob->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.tx_addr, GFP_KERNEL); ++ if (!oob->dma.tx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } ++ ++ oob->dma.rxd_virt = dmam_alloc_coherent(dev, ++ sizeof(struct ast2700_espi_oob_dma_rx_desc) * ++ OOB_DMA_DESC_NUM, ++ &oob->dma.rxd_addr, GFP_KERNEL); ++ if (!oob->dma.rxd_virt) { ++ dev_err(dev, "cannot allocate DMA RX descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ oob->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.rx_addr, GFP_KERNEL); ++ if (!oob->dma.rx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } + } + -+ return otp_prog_bit(ctx, value, prog_address, bit_offset); -+} ++ oob->mdev.parent = dev; ++ oob->mdev.minor = MISC_DYNAMIC_MINOR; ++ oob->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-oob%d", DEVICE_NAME, espi->dev_id); ++ oob->mdev.fops = &ast2700_espi_oob_fops; ++ rc = misc_register(&oob->mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", oob->mdev.name); ++ return rc; ++ } + -+struct aspeed_otp *glob_ctx; ++ ast2700_espi_oob_reset(espi); + -+void otp_read_data_buf(u32 offset, u32 *buf, u32 len) ++ return 0; ++} ++ ++int ast2700_espi_oob_remove(struct aspeed_espi *espi) +{ -+ int i, j; -+ u32 ret[2]; ++ struct aspeed_espi_oob *oob; ++ struct device *dev; ++ u32 reg; + -+ aspeed_otp_write(glob_ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++ dev = espi->dev; + -+ otp_soak(glob_ctx, 0); ++ oob = &espi->oob; + -+ i = offset; -+ j = 0; -+ if (offset % 2) { -+ otp_read_data_2dw(glob_ctx, i - 1, ret); -+ buf[0] = ret[1]; -+ i++; -+ j++; ++ writel(0x0, espi->regs + ESPI_CH2_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CH2_CTRL); ++ reg &= ~(ESPI_CH2_CTRL_TX_DMA_EN ++ | ESPI_CH2_CTRL_RX_DMA_EN ++ | ESPI_CH2_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ ++ if (oob->dma.enable) { ++ dmam_free_coherent(dev, sizeof(struct ast2700_espi_oob_dma_tx_desc) * OOB_DMA_DESC_NUM, ++ oob->dma.txd_virt, oob->dma.txd_addr); ++ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, ++ oob->dma.tx_virt, oob->dma.tx_addr); ++ dmam_free_coherent(dev, sizeof(struct ast2700_espi_oob_dma_rx_desc) * OOB_DMA_DESC_NUM, ++ oob->dma.rxd_virt, oob->dma.rxd_addr); ++ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, ++ oob->dma.rx_virt, oob->dma.rx_addr); + } -+ for (; j < len; i += 2, j += 2) -+ otp_read_data_2dw(glob_ctx, i, &buf[j]); -+ aspeed_otp_write(glob_ctx, 0, OTP_PROTECT_KEY); -+} -+EXPORT_SYMBOL(otp_read_data_buf); + -+void otp_read_conf_buf(u32 offset, u32 *buf, u32 len) -+{ -+ int i, j; ++ mutex_destroy(&oob->tx_mtx); ++ mutex_destroy(&oob->rx_mtx); + -+ aspeed_otp_write(glob_ctx, OTP_PASSWD, OTP_PROTECT_KEY); -+ otp_soak(glob_ctx, 0); -+ for (i = offset, j = 0; j < len; i++, j++) -+ otp_read_conf_dw(glob_ctx, i, &buf[j]); -+ aspeed_otp_write(glob_ctx, 0, OTP_PROTECT_KEY); ++ misc_deregister(&oob->mdev); ++ ++ return 0; +} -+EXPORT_SYMBOL(otp_read_conf_buf); + -+static long otp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++/* flash channel (CH3) */ ++static long ast2700_espi_flash_get_rx(struct file *fp, ++ struct aspeed_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); -+ void __user *argp = (void __user *)arg; -+ struct otp_read xfer; -+ struct otp_prog prog; -+ u32 reg_read[2]; -+ int ret = 0; -+ -+ switch (cmd) { -+ case ASPEED_OTP_READ_DATA: -+ if (copy_from_user(&xfer, argp, sizeof(struct otp_read))) -+ return -EFAULT; -+ if ((xfer.offset + xfer.len) > 0x800) { -+ pr_err("out of range"); -+ return -EINVAL; -+ } ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ unsigned long flags; ++ u32 pkt_len; ++ u8 *pkt; ++ int i, rc; + -+ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); -+ otp_read_data(ctx, xfer.offset, xfer.len); -+ aspeed_otp_write(ctx, 0, OTP_PROTECT_KEY); ++ rc = 0; + -+ if (copy_to_user(xfer.data, ctx->data, xfer.len * 4)) -+ return -EFAULT; -+ if (copy_to_user(argp, &xfer, sizeof(struct otp_read))) -+ return -EFAULT; -+ break; -+ case ASPEED_OTP_READ_CONF: -+ if (copy_from_user(&xfer, argp, sizeof(struct otp_read))) -+ return -EFAULT; -+ if ((xfer.offset + xfer.len) > 0x800) { -+ pr_err("out of range"); -+ return -EINVAL; -+ } ++ espi = container_of(flash, struct aspeed_espi, flash); + -+ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); -+ otp_read_conf(ctx, xfer.offset, xfer.len); -+ aspeed_otp_write(ctx, 0, OTP_PROTECT_KEY); ++ if (fp->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&flash->rx_mtx)) ++ return -EAGAIN; + -+ if (copy_to_user(xfer.data, ctx->data, xfer.len * 4)) -+ return -EFAULT; -+ if (copy_to_user(argp, &xfer, sizeof(struct otp_read))) -+ return -EFAULT; -+ break; -+ case ASPEED_OTP_PROG_DATA: -+ if (copy_from_user(&prog, argp, sizeof(struct otp_prog))) -+ return -EFAULT; -+ if (prog.bit_offset >= 32 || (prog.value != 0 && prog.value != 1)) { -+ pr_err("out of range"); -+ return -EINVAL; -+ } -+ if (prog.dw_offset >= 0x800) { -+ pr_err("out of range"); -+ return -EINVAL; -+ } -+ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); -+ ret = otp_prog_data(ctx, prog.value, prog.dw_offset, prog.bit_offset); -+ break; -+ case ASPEED_OTP_PROG_CONF: -+ if (copy_from_user(&prog, argp, sizeof(struct otp_prog))) -+ return -EFAULT; -+ if (prog.bit_offset >= 32 || (prog.value != 0 && prog.value != 1)) { -+ pr_err("out of range"); -+ return -EINVAL; ++ if (!flash->rx_ready) { ++ rc = -ENODATA; ++ goto unlock_mtx_n_out; + } -+ if (prog.dw_offset >= 0x20) { -+ pr_err("out of range"); -+ return -EINVAL; ++ } else { ++ mutex_lock(&flash->rx_mtx); ++ ++ if (!flash->rx_ready) { ++ rc = wait_event_interruptible(flash->wq, flash->rx_ready); ++ if (rc == -ERESTARTSYS) { ++ rc = -EINTR; ++ goto unlock_mtx_n_out; ++ } + } -+ aspeed_otp_write(ctx, OTP_PASSWD, OTP_PROTECT_KEY); -+ ret = otp_prog_conf(ctx, prog.value, prog.dw_offset, prog.bit_offset); ++ } ++ ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ reg = readl(espi->regs + ESPI_CH3_RX_CTRL); ++ cyc = FIELD_GET(ESPI_CH3_RX_CTRL_CYC, reg); ++ tag = FIELD_GET(ESPI_CH3_RX_CTRL_TAG, reg); ++ len = FIELD_GET(ESPI_CH3_RX_CTRL_LEN, reg); ++ ++ /* ++ * calculate the length of the rest part of the ++ * eSPI packet to be read from HW and copied to ++ * user space. ++ */ ++ switch (cyc) { ++ case ESPI_FLASH_WRITE: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_flash_rwe); + break; -+ case ASPEED_OTP_VER: -+ if (copy_to_user(argp, &ctx->otp_ver, sizeof(u32))) -+ return -EFAULT; ++ case ESPI_FLASH_READ: ++ case ESPI_FLASH_ERASE: ++ pkt_len = sizeof(struct espi_flash_rwe); + break; -+ case ASPEED_OTP_SW_RID: -+ reg_read[0] = aspeed_otp_read(ctx, SW_REV_ID0); -+ reg_read[1] = aspeed_otp_read(ctx, SW_REV_ID1); -+ if (copy_to_user(argp, reg_read, sizeof(u32) * 2)) -+ return -EFAULT; ++ case ESPI_FLASH_SUC_CMPLT_D_MIDDLE: ++ case ESPI_FLASH_SUC_CMPLT_D_FIRST: ++ case ESPI_FLASH_SUC_CMPLT_D_LAST: ++ case ESPI_FLASH_SUC_CMPLT_D_ONLY: ++ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + ++ sizeof(struct espi_flash_cmplt); + break; -+ case ASPEED_SEC_KEY_NUM: -+ reg_read[0] = aspeed_otp_read(ctx, SEC_KEY_NUM) & 7; -+ if (copy_to_user(argp, reg_read, sizeof(u32))) -+ return -EFAULT; ++ case ESPI_FLASH_SUC_CMPLT: ++ case ESPI_FLASH_UNSUC_CMPLT: ++ pkt_len = sizeof(struct espi_flash_cmplt); + break; ++ default: ++ rc = -EFAULT; ++ goto unlock_mtx_n_out; + } -+ return ret; -+} -+ -+static int otp_open(struct inode *inode, struct file *file) -+{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ spin_lock(&otp_state_lock); ++ if (ioc->pkt_len < pkt_len) { ++ rc = -EINVAL; ++ goto unlock_mtx_n_out; ++ } + -+ if (ctx->is_open) { -+ spin_unlock(&otp_state_lock); -+ return -EBUSY; ++ pkt = vmalloc(pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; + } + -+ ctx->is_open = true; ++ hdr = (struct espi_comm_hdr *)pkt; ++ hdr->cyc = cyc; ++ hdr->tag = tag; ++ hdr->len_h = len >> 8; ++ hdr->len_l = len & 0xff; + -+ spin_unlock(&otp_state_lock); ++ if (flash->dma.enable) { ++ memcpy(hdr + 1, flash->dma.rx_virt, pkt_len - sizeof(*hdr)); ++ } else { ++ for (i = sizeof(*hdr); i < pkt_len; ++i) ++ pkt[i] = readl(espi->regs + ESPI_CH3_RX_DATA) & 0xff; ++ } + -+ return 0; -+} ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+static int otp_release(struct inode *inode, struct file *file) -+{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++ spin_lock_irqsave(&flash->lock, flags); + -+ spin_lock(&otp_state_lock); ++ writel(ESPI_CH3_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH3_RX_CTRL); ++ flash->rx_ready = 0; + -+ ctx->is_open = false; ++ spin_unlock_irqrestore(&flash->lock, flags); + -+ spin_unlock(&otp_state_lock); ++ rc = 0; + -+ return 0; -+} ++free_n_out: ++ vfree(pkt); + -+static const struct file_operations otp_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = otp_ioctl, -+ .open = otp_open, -+ .release = otp_release, -+}; ++unlock_mtx_n_out: ++ mutex_unlock(&flash->rx_mtx); + -+static const struct of_device_id aspeed_otp_of_matches[] = { -+ { .compatible = "aspeed,ast2600-sbc" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); ++ return rc; ++} + -+static int aspeed_otp_probe(struct platform_device *pdev) ++static long ast2700_espi_flash_put_tx(struct file *fp, ++ struct aspeed_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ struct device *dev = &pdev->dev; -+ struct regmap *scu; -+ struct aspeed_otp *priv; -+ struct resource *res; -+ u32 revid0, revid1; -+ int rc; ++ u32 reg, cyc, tag, len; ++ struct aspeed_espi *espi; ++ struct espi_comm_hdr *hdr; ++ u8 *pkt; ++ int i, rc; + -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ glob_ctx = priv; -+ if (!priv) -+ return -ENOMEM; ++ espi = container_of(flash, struct aspeed_espi, flash); + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); -+ return -ENOENT; -+ } ++ if (!mutex_trylock(&flash->tx_mtx)) ++ return -EAGAIN; + -+ priv->reg_base = devm_ioremap_resource(&pdev->dev, res); -+ if (!priv->reg_base) -+ return -EIO; ++ reg = readl(espi->regs + ESPI_CH3_TX_CTRL); ++ if (reg & ESPI_CH3_TX_CTRL_TRIG_PEND) { ++ rc = -EBUSY; ++ goto unlock_mtx_n_out; ++ } + -+ scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); -+ if (IS_ERR(scu)) { -+ dev_err(dev, "failed to find 2600 SCU regmap\n"); -+ return PTR_ERR(scu); ++ pkt = vmalloc(ioc->pkt_len); ++ if (!pkt) { ++ rc = -ENOMEM; ++ goto unlock_mtx_n_out; + } + -+ regmap_read(scu, ASPEED_REVISION_ID0, &revid0); -+ regmap_read(scu, ASPEED_REVISION_ID1, &revid1); ++ hdr = (struct espi_comm_hdr *)pkt; + -+ priv->otp_ver = chip_version(revid0, revid1); ++ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } + -+ if (priv->otp_ver == -1) { -+ dev_err(dev, "invalid SCU\n"); -+ return -EINVAL; ++ /* ++ * common header (i.e. cycle type, tag, and length) ++ * part is written to HW registers ++ */ ++ if (flash->dma.enable) { ++ memcpy(flash->dma.tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ dma_wmb(); ++ } else { ++ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) ++ writel(pkt[i], espi->regs + ESPI_CH3_TX_DATA); + } + -+ priv->data = kmalloc(8192, GFP_KERNEL); -+ if (!priv->data) -+ return -ENOMEM; ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ dev_set_drvdata(dev, priv); ++ reg = FIELD_PREP(ESPI_CH3_TX_CTRL_CYC, cyc) ++ | FIELD_PREP(ESPI_CH3_TX_CTRL_TAG, tag) ++ | FIELD_PREP(ESPI_CH3_TX_CTRL_LEN, len) ++ | ESPI_CH3_TX_CTRL_TRIG_PEND; ++ writel(reg, espi->regs + ESPI_CH3_TX_CTRL); + -+ /* Set up the miscdevice */ -+ priv->miscdev.minor = MISC_DYNAMIC_MINOR; -+ priv->miscdev.name = "aspeed-otp"; -+ priv->miscdev.fops = &otp_fops; ++ rc = 0; + -+ /* Register the device */ -+ rc = misc_register(&priv->miscdev); -+ if (rc) { -+ dev_err(dev, "Unable to register device\n"); -+ return rc; -+ } ++free_n_out: ++ vfree(pkt); + -+ return 0; ++unlock_mtx_n_out: ++ mutex_unlock(&flash->tx_mtx); ++ ++ return rc; +} + -+static void aspeed_otp_remove(struct platform_device *pdev) ++static long ast2700_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); ++ struct aspeed_espi_flash *flash; ++ struct aspeed_espi_ioc ioc; + -+ kfree(ctx->data); -+ misc_deregister(&ctx->miscdev); ++ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); ++ ++ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) ++ return -EFAULT; ++ ++ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case ASPEED_ESPI_FLASH_GET_RX: ++ return ast2700_espi_flash_get_rx(fp, flash, &ioc); ++ case ASPEED_ESPI_FLASH_PUT_TX: ++ return ast2700_espi_flash_put_tx(fp, flash, &ioc); ++ }; ++ ++ return -EINVAL; +} + -+static struct platform_driver aspeed_otp_driver = { -+ .probe = aspeed_otp_probe, -+ .remove = aspeed_otp_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_otp_of_matches, -+ }, ++static const struct file_operations ast2700_espi_flash_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2700_espi_flash_ioctl, +}; + -+module_platform_driver(aspeed_otp_driver); ++static void ast2700_espi_flash_isr(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_flash *flash; ++ unsigned long flags; ++ u32 sts; + -+MODULE_AUTHOR("Neal Liu "); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("ASPEED OTP Driver"); -diff --git a/drivers/soc/aspeed/ast2700-espi.c b/drivers/soc/aspeed/ast2700-espi.c ---- a/drivers/soc/aspeed/ast2700-espi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2700-espi.c 2025-12-23 10:16:21.126032636 +0000 -@@ -0,0 +1,2304 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ flash = &espi->flash; + -+#include "ast2700-espi.h" ++ sts = readl(espi->regs + ESPI_CH3_INT_STS); + -+#define DEVICE_NAME "aspeed-espi" ++ if (sts & ESPI_CH3_INT_STS_RX_CMPLT) { ++ writel(ESPI_CH3_INT_STS_RX_CMPLT, espi->regs + ESPI_CH3_INT_STS); + -+static DEFINE_IDA(ast2700_espi_ida); ++ spin_lock_irqsave(&flash->lock, flags); ++ flash->rx_ready = true; ++ spin_unlock_irqrestore(&flash->lock, flags); + -+#define PERIF_MCYC_ALIGN SZ_64K -+#define PERIF_MMBI_ALIGN SZ_64M -+#define PERIF_MMBI_MAX_INST 8 ++ wake_up_interruptible(&flash->wq); ++ } ++} + -+#define OOB_DMA_RPTR_KEY 0x4f4f4253 -+#define OOB_DMA_DESC_NUM 8 -+#define OOB_DMA_DESC_CUSTOM 0x4 ++static void ast2700_espi_flash_reset(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ u64 mask; ++ struct aspeed_espi_flash *flash = &espi->flash; + -+#define FLASH_EDAF_ALIGN SZ_16M ++ writel(0x0, espi->regs + ESPI_CH3_INT_EN); ++ writel(0xffffffff, espi->regs + ESPI_CH3_INT_STS); + -+struct ast2700_espi_perif_mmbi { -+ void *b2h_virt; -+ void *h2b_virt; -+ dma_addr_t b2h_addr; -+ dma_addr_t h2b_addr; -+ struct miscdevice b2h_mdev; -+ struct miscdevice h2b_mdev; -+ bool host_rwp_update; -+ wait_queue_head_t wq; -+ struct ast2700_espi_perif *perif; -+}; ++ reg = readl(espi->regs + ESPI_CH3_CTRL); ++ reg &= ~(ESPI_CH3_CTRL_TX_RST ++ | ESPI_CH3_CTRL_RX_RST ++ | ESPI_CH3_CTRL_TX_DMA_EN ++ | ESPI_CH3_CTRL_RX_DMA_EN ++ | ESPI_CH3_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH3_CTRL); + -+struct ast2700_espi_perif { -+ struct { -+ bool enable; -+ int irq; -+ void *virt; -+ dma_addr_t taddr; -+ uint64_t saddr; -+ uint64_t size; -+ uint32_t inst_num; -+ uint32_t inst_size; -+ struct ast2700_espi_perif_mmbi inst[PERIF_MMBI_MAX_INST]; -+ } mmbi; ++ udelay(1); + -+ struct { -+ bool enable; -+ void *virt; -+ dma_addr_t taddr; -+ uint64_t saddr; -+ uint64_t size; -+ } mcyc; ++ reg |= (ESPI_CH3_CTRL_TX_RST | ESPI_CH3_CTRL_RX_RST); ++ writel(reg, espi->regs + ESPI_CH3_CTRL); + -+ struct { -+ bool enable; -+ void *np_tx_virt; -+ dma_addr_t np_tx_addr; -+ void *pc_tx_virt; -+ dma_addr_t pc_tx_addr; -+ void *pc_rx_virt; -+ dma_addr_t pc_rx_addr; -+ } dma; ++ if (flash->edaf.mode == EDAF_MODE_MIX) { ++ mask = ~(flash->edaf.size - 1); ++ writel(upper_32_bits(mask), espi->regs + ESPI_CH3_EDAF_MASKH); ++ writel(mask & 0xffffffff, espi->regs + ESPI_CH3_EDAF_MASKL); ++ writel(upper_32_bits(flash->edaf.taddr), espi->regs + ESPI_CH3_EDAF_TADDRH); ++ writel(flash->edaf.taddr & 0xffffffff, espi->regs + ESPI_CH3_EDAF_TADDRL); ++ } + -+ bool rtc_enable; -+ bool rx_ready; -+ wait_queue_head_t wq; ++ reg = readl(espi->regs + ESPI_CH3_CTRL) & ~ESPI_CH3_CTRL_EDAF_MODE; ++ reg |= FIELD_PREP(ESPI_CH3_CTRL_EDAF_MODE, flash->edaf.mode); ++ writel(reg, espi->regs + ESPI_CH3_CTRL); + -+ spinlock_t lock; -+ struct mutex np_tx_mtx; -+ struct mutex pc_tx_mtx; -+ struct mutex pc_rx_mtx; ++ if (flash->dma.enable) { ++ writel(upper_32_bits(flash->dma.tx_addr), espi->regs + ESPI_CH3_TX_DMAH); ++ writel(flash->dma.tx_addr & 0xffffffff, espi->regs + ESPI_CH3_TX_DMAL); ++ writel(upper_32_bits(flash->dma.rx_addr), espi->regs + ESPI_CH3_RX_DMAH); ++ writel(flash->dma.rx_addr & 0xffffffff, espi->regs + ESPI_CH3_RX_DMAL); + -+ struct miscdevice mdev; -+}; ++ reg = readl(espi->regs + ESPI_CH3_CTRL) ++ | ESPI_CH3_CTRL_TX_DMA_EN ++ | ESPI_CH3_CTRL_RX_DMA_EN; ++ writel(reg, espi->regs + ESPI_CH3_CTRL); ++ } ++ ++ writel(ESPI_CH3_INT_EN_RX_CMPLT, espi->regs + ESPI_CH3_INT_EN); ++ ++ reg = readl(espi->regs + ESPI_CH3_CTRL) | ESPI_CH3_CTRL_SW_RDY; ++ writel(reg, espi->regs + ESPI_CH3_CTRL); ++} ++ ++int ast2700_espi_flash_probe(struct aspeed_espi *espi) ++{ ++ struct aspeed_espi_flash *flash; ++ struct device_node *np; ++ struct resource res; ++ struct device *dev; ++ void *virt; ++ int rc; + -+struct ast2700_espi_vw { -+ struct { -+ bool hw_mode; -+ uint32_t grp; -+ uint32_t dir0; -+ uint32_t dir1; -+ uint32_t val0; -+ uint32_t val1; -+ } gpio; ++ dev = espi->dev; + -+ struct miscdevice mdev; -+}; ++ flash = &espi->flash; + -+struct ast2700_espi_oob_dma_tx_desc { -+ uint32_t data_addrl; -+ uint32_t data_addrh; -+ uint8_t cyc; -+ uint16_t tag : 4; -+ uint16_t len : 12; -+ uint8_t msg_type : 3; -+ uint8_t raz0 : 1; -+ uint8_t pec : 1; -+ uint8_t int_en : 1; -+ uint8_t pause : 1; -+ uint8_t raz1 : 1; -+ uint32_t raz2; -+ uint32_t raz3; -+ uint32_t pad[3]; -+} __packed; ++ init_waitqueue_head(&flash->wq); + -+struct ast2700_espi_oob_dma_rx_desc { -+ uint32_t data_addrl; -+ uint32_t data_addrh; -+ uint8_t cyc; -+ uint16_t tag : 4; -+ uint16_t len : 12; -+ uint8_t raz : 7; -+ uint8_t dirty : 1; -+ uint32_t pad[1]; -+} __packed; ++ spin_lock_init(&flash->lock); + -+struct ast2700_espi_oob { -+ struct { -+ bool enable; -+ struct ast2700_espi_oob_dma_tx_desc *txd_virt; -+ dma_addr_t txd_addr; -+ struct ast2700_espi_oob_dma_rx_desc *rxd_virt; -+ dma_addr_t rxd_addr; -+ void *tx_virt; -+ dma_addr_t tx_addr; -+ void *rx_virt; -+ dma_addr_t rx_addr; -+ } dma; ++ mutex_init(&flash->tx_mtx); ++ mutex_init(&flash->rx_mtx); + -+ bool rx_ready; -+ wait_queue_head_t wq; ++ flash->edaf.mode = EDAF_MODE_HW; + -+ spinlock_t lock; -+ struct mutex tx_mtx; -+ struct mutex rx_mtx; ++ of_property_read_u32(dev->of_node, "flash-edaf-mode", &flash->edaf.mode); ++ dev_info(dev, "eDAF mode: 0x%x\n", flash->edaf.mode); ++ if (flash->edaf.mode == EDAF_MODE_MIX) { ++ np = of_parse_phandle(dev->of_node, "flash-edaf-tgt-addr", 0); ++ if (!np || of_address_to_resource(np, 0, &res)) { ++ dev_err(dev, "cannot get eDAF memory region\n"); ++ return -ENODEV; ++ } + -+ struct miscdevice mdev; -+}; ++ of_node_put(np); + -+struct ast2700_espi_flash { -+ struct { -+ uint32_t mode; -+ phys_addr_t taddr; -+ uint64_t size; -+ } edaf; ++ flash->edaf.taddr = res.start; ++ flash->edaf.size = resource_size(&res); + -+ struct { -+ bool enable; -+ void *tx_virt; -+ dma_addr_t tx_addr; -+ void *rx_virt; -+ dma_addr_t rx_addr; -+ } dma; ++ virt = devm_ioremap_resource(dev, &res); ++ if (!virt) { ++ dev_err(dev, "cannot map eDAF memory region\n"); ++ return -ENOMEM; ++ } ++ } + -+ bool rx_ready; -+ wait_queue_head_t wq; ++ flash->dma.enable = of_property_read_bool(dev->of_node, "flash-dma-mode"); ++ if (flash->dma.enable) { ++ flash->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.tx_addr, GFP_KERNEL); ++ if (!flash->dma.tx_virt) { ++ dev_err(dev, "cannot allocate DMA TX buffer\n"); ++ return -ENOMEM; ++ } + -+ spinlock_t lock; -+ struct mutex rx_mtx; -+ struct mutex tx_mtx; ++ flash->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.rx_addr, GFP_KERNEL); ++ if (!flash->dma.rx_virt) { ++ dev_err(dev, "cannot allocate DMA RX buffer\n"); ++ return -ENOMEM; ++ } ++ } + -+ struct miscdevice mdev; -+}; ++ flash->mdev.parent = dev; ++ flash->mdev.minor = MISC_DYNAMIC_MINOR; ++ flash->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-flash%d", DEVICE_NAME, espi->dev_id); ++ flash->mdev.fops = &ast2700_espi_flash_fops; ++ rc = misc_register(&flash->mdev); ++ if (rc) { ++ dev_err(dev, "cannot register device %s\n", flash->mdev.name); ++ return rc; ++ } + -+struct ast2700_espi { -+ struct device *dev; -+ void __iomem *regs; -+ struct clk *clk; -+ int dev_id; -+ int irq; ++ ast2700_espi_flash_reset(espi); + -+ struct ast2700_espi_perif perif; -+ struct ast2700_espi_vw vw; -+ struct ast2700_espi_oob oob; -+ struct ast2700_espi_flash flash; -+}; ++ return 0; ++} + -+/* peripheral channel (CH0) */ -+static int ast2700_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vma) ++int ast2700_espi_flash_remove(struct aspeed_espi *espi) +{ -+ struct ast2700_espi_perif_mmbi *mmbi; -+ struct ast2700_espi_perif *perif; -+ struct ast2700_espi *espi; -+ unsigned long vm_size; -+ pgprot_t prot; ++ struct aspeed_espi_flash *flash; ++ struct device *dev; ++ u32 reg; + -+ mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, b2h_mdev); ++ dev = espi->dev; + -+ perif = mmbi->perif; ++ flash = &espi->flash; + -+ espi = container_of(perif, struct ast2700_espi, perif); ++ writel(0x0, espi->regs + ESPI_CH3_INT_EN); + -+ vm_size = vma->vm_end - vma->vm_start; -+ prot = vma->vm_page_prot; ++ reg = readl(espi->regs + ESPI_CH3_CTRL); ++ reg &= ~(ESPI_CH3_CTRL_TX_DMA_EN ++ | ESPI_CH3_CTRL_RX_DMA_EN ++ | ESPI_CH3_CTRL_SW_RDY); ++ writel(reg, espi->regs + ESPI_CH3_CTRL); + -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > (perif->mmbi.inst_size >> 1)) -+ return -EINVAL; ++ if (flash->dma.enable) { ++ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.tx_addr); ++ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.rx_addr); ++ } + -+ prot = pgprot_noncached(prot); ++ mutex_destroy(&flash->tx_mtx); ++ mutex_destroy(&flash->rx_mtx); + -+ if (remap_pfn_range(vma, vma->vm_start, -+ (mmbi->b2h_addr >> PAGE_SHIFT) + vma->vm_pgoff, -+ vm_size, prot)) -+ return -EAGAIN; ++ misc_deregister(&flash->mdev); + + return 0; +} + -+static int ast2700_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) ++/* global control */ ++irqreturn_t ast2700_espi_isr(int irq, void *arg) +{ -+ struct ast2700_espi_perif_mmbi *mmbi; -+ struct ast2700_espi_perif *perif; -+ struct ast2700_espi *espi; -+ unsigned long vm_size; -+ pgprot_t prot; -+ -+ mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, h2b_mdev); ++ u32 sts; ++ struct aspeed_espi *espi = (struct aspeed_espi *)arg; + -+ perif = mmbi->perif; ++ sts = readl(espi->regs + ESPI_INT_STS); ++ if (!sts) ++ return IRQ_NONE; + -+ espi = container_of(perif, struct ast2700_espi, perif); ++ if (sts & ESPI_INT_STS_CH0) ++ ast2700_espi_perif_isr(espi); + -+ vm_size = vma->vm_end - vma->vm_start; -+ prot = vma->vm_page_prot; ++ if (sts & ESPI_INT_STS_CH1) ++ ast2700_espi_vw_isr(espi); + -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > (perif->mmbi.inst_size >> 1)) -+ return -EINVAL; ++ if (sts & ESPI_INT_STS_CH2) ++ ast2700_espi_oob_isr(espi); + -+ prot = pgprot_noncached(prot); ++ if (sts & ESPI_INT_STS_CH3) ++ ast2700_espi_flash_isr(espi); + -+ if (remap_pfn_range(vma, vma->vm_start, -+ (mmbi->h2b_addr >> PAGE_SHIFT) + vma->vm_pgoff, -+ vm_size, prot)) -+ return -EAGAIN; ++ if (sts & ESPI_INT_STS_RST_DEASSERT) { ++ ast2700_espi_perif_sw_reset(espi); ++ ast2700_espi_perif_reset(espi); ++ ast2700_espi_vw_reset(espi); ++ ast2700_espi_oob_reset(espi); ++ ast2700_espi_flash_reset(espi); ++ writel(ESPI_INT_STS_RST_DEASSERT, espi->regs + ESPI_INT_STS); ++ } + -+ return 0; ++ return IRQ_HANDLED; +} + -+static __poll_t ast2700_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) ++void ast2700_espi_pre_init(struct aspeed_espi *espi) +{ -+ struct ast2700_espi_perif_mmbi *mmbi; ++ struct device *dev; ++ struct regmap *scu1; ++ u32 reg; ++ int rc; + -+ mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, h2b_mdev); ++ dev = espi->dev; + -+ poll_wait(fp, &mmbi->wq, pt); ++ scu1 = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,syscon"); ++ if (IS_ERR(scu1)) { ++ dev_err(dev, "failed to find SCU1 regmap, error %ld\n", PTR_ERR(scu1)); ++ return; ++ } ++ rc = regmap_update_bits(scu1, SCU1_DDR, ++ SCU1_DDR_DIS_ESPI0_AHB | SCU1_DDR_DIS_ESPI1_AHB, ++ 0); ++ if (rc) { ++ dev_err(dev, "failed to update SCU1 regmap, error %d\n", rc); ++ return; ++ } + -+ if (!mmbi->host_rwp_update) -+ return 0; ++ espi->dev_id = ida_alloc(&ast2700_espi_ida, GFP_KERNEL); ++ if (espi->dev_id < 0) { ++ dev_err(dev, "cannote allocate device ID, error %d\n", espi->dev_id); ++ return; ++ } + -+ mmbi->host_rwp_update = false; ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~ESPI_INT_EN_RST_DEASSERT; ++ writel(reg, espi->regs + ESPI_INT_EN); ++} + -+ return EPOLLIN; ++void ast2700_espi_post_init(struct aspeed_espi *espi) ++{ ++ u32 reg; ++ ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg |= ESPI_INT_EN_RST_DEASSERT; ++ writel(reg, espi->regs + ESPI_INT_EN); +} + -+static long ast2700_espi_perif_pc_get_rx(struct file *fp, -+ struct ast2700_espi_perif *perif, -+ struct aspeed_espi_ioc *ioc) ++void ast2700_espi_deinit(struct aspeed_espi *espi) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; -+ int i, rc; ++ struct device *dev; ++ u32 reg; + -+ espi = container_of(perif, struct ast2700_espi, perif); ++ dev = espi->dev; + -+ if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&perif->pc_rx_mtx)) -+ return -EAGAIN; ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~ESPI_INT_EN_RST_DEASSERT; ++ writel(reg, espi->regs + ESPI_INT_EN); ++} +diff --git a/drivers/soc/aspeed/espi/ast2700-espi.h b/drivers/soc/aspeed/espi/ast2700-espi.h +--- a/drivers/soc/aspeed/espi/ast2700-espi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2700-espi.h 2026-09-09 15:51:44.720238041 +0000 +@@ -0,0 +1,300 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Register definitions for Aspeed AST2700 eSPI controller ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#ifndef _AST2700_ESPI_H_ ++#define _AST2700_ESPI_H_ + -+ if (!perif->rx_ready) { -+ rc = -ENODATA; -+ goto unlock_mtx_n_out; -+ } -+ } else { -+ mutex_lock(&perif->pc_rx_mtx); ++#include ++#include "aspeed-espi.h" + -+ if (!perif->rx_ready) { -+ rc = wait_event_interruptible(perif->wq, perif->rx_ready); -+ if (rc == -ERESTARTSYS) { -+ rc = -EINTR; -+ goto unlock_mtx_n_out; -+ } -+ } -+ } ++/* SCU regiseters */ ++#define SCU1_DDR 0x0c8 ++#define SCU1_DDR_DIS_ESPI0_AHB BIT(0) ++#define SCU1_DDR_DIS_ESPI1_AHB BIT(1) + -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ reg = readl(espi->regs + ESPI_CH0_PC_RX_CTRL); -+ cyc = FIELD_GET(ESPI_CH0_PC_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_CH0_PC_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_CH0_PC_RX_CTRL_LEN, reg); ++/* global registers */ ++#define ESPI_CTRL 0x000 ++#define ESPI_STS 0x004 ++#define ESPI_INT_STS 0x008 ++#define ESPI_INT_STS_RST_DEASSERT BIT(31) ++#define ESPI_INT_STS_RST_ASSERT BIT(30) ++#define ESPI_INT_STS_CH3 BIT(3) ++#define ESPI_INT_STS_CH2 BIT(2) ++#define ESPI_INT_STS_CH1 BIT(1) ++#define ESPI_INT_STS_CH0 BIT(0) ++#define ESPI_INT_EN 0x00c ++#define ESPI_INT_EN_RST_DEASSERT BIT(31) ++#define ESPI_INT_EN_RST_ASSERT BIT(30) ++#define ESPI_DEV_ID 0x010 ++#define ESPI_CAP_GEN 0x014 ++#define ESPI_CAP_GEN_RTC_SUP BIT(29) ++#define ESPI_CAP_CH0 0x018 ++#define ESPI_CAP_CH1 0x01c ++#define ESPI_CAP_CH2 0x020 ++#define ESPI_CAP_CH3_0 0x024 ++#define ESPI_CAP_CH3_1 0x028 ++#define ESPI_DEV_STS 0x030 ++#define ESPI_DBG_CTRL 0x034 ++#define ESPI_DBG_ADDRL 0x038 ++#define ESPI_DBG_ADDRH 0x03c ++#define ESPI_DBG_CMD 0x040 ++#define ESPI_DBG_RES 0x044 ++#define ESPI_CH_ACC_CTRL 0x04c ++#define ESPI_CH_ACC_OFST1 0x050 ++#define ESPI_CH_ACC_OFST2 0x054 ++#define ESPI_WPROT0 0x0f8 ++#define ESPI_WPROT1 0x0fc + -+ /* -+ * calculate the length of the rest part of the -+ * eSPI packet to be read from HW and copied to -+ * user space. -+ */ -+ switch (cyc) { -+ case ESPI_PERIF_MSG: -+ pkt_len = sizeof(struct espi_perif_msg); -+ break; -+ case ESPI_PERIF_MSG_D: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_perif_msg); -+ break; -+ case ESPI_PERIF_SUC_CMPLT_D_MIDDLE: -+ case ESPI_PERIF_SUC_CMPLT_D_FIRST: -+ case ESPI_PERIF_SUC_CMPLT_D_LAST: -+ case ESPI_PERIF_SUC_CMPLT_D_ONLY: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_perif_cmplt); -+ break; -+ case ESPI_PERIF_SUC_CMPLT: -+ case ESPI_PERIF_UNSUC_CMPLT: -+ pkt_len = sizeof(struct espi_perif_cmplt); -+ break; -+ default: -+ rc = -EFAULT; -+ goto unlock_mtx_n_out; -+ } ++/* peripheral channel (ch0) registers */ ++#define ESPI_CH0_CTRL 0x100 ++#define ESPI_CH0_CTRL_NP_TX_RST BIT(31) ++#define ESPI_CH0_CTRL_NP_RX_RST BIT(30) ++#define ESPI_CH0_CTRL_PC_TX_RST BIT(29) ++#define ESPI_CH0_CTRL_PC_RX_RST BIT(28) ++#define ESPI_CH0_CTRL_NP_TX_DMA_EN BIT(19) ++#define ESPI_CH0_CTRL_PC_TX_DMA_EN BIT(17) ++#define ESPI_CH0_CTRL_PC_RX_DMA_EN BIT(16) ++#define ESPI_CH0_CTRL_MCYC_RD_DIS_WDT BIT(9) ++#define ESPI_CH0_CTRL_MCYC_WR_DIS_WDT BIT(8) ++#define ESPI_CH0_CTRL_MCYC_RD_DIS BIT(6) ++#define ESPI_CH0_CTRL_MCYC_WR_DIS BIT(4) ++#define ESPI_CH0_CTRL_SW_RDY BIT(1) ++#define ESPI_CH0_STS 0x104 ++#define ESPI_CH0_INT_STS 0x108 ++#define ESPI_CH0_INT_STS_PC_RX_CMPLT BIT(0) ++#define ESPI_CH0_INT_EN 0x10c ++#define ESPI_CH0_INT_EN_PC_RX_CMPLT BIT(0) ++#define ESPI_CH0_PC_RX_DMAL 0x110 ++#define ESPI_CH0_PC_RX_DMAH 0x114 ++#define ESPI_CH0_PC_RX_CTRL 0x118 ++#define ESPI_CH0_PC_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_CH0_PC_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH0_PC_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH0_PC_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH0_PC_RX_DATA 0x11c ++#define ESPI_CH0_PC_TX_DMAL 0x120 ++#define ESPI_CH0_PC_TX_DMAH 0x124 ++#define ESPI_CH0_PC_TX_CTRL 0x128 ++#define ESPI_CH0_PC_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_CH0_PC_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH0_PC_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH0_PC_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH0_PC_TX_DATA 0x12c ++#define ESPI_CH0_NP_TX_DMAL 0x130 ++#define ESPI_CH0_NP_TX_DMAH 0x134 ++#define ESPI_CH0_NP_TX_CTRL 0x138 ++#define ESPI_CH0_NP_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_CH0_NP_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH0_NP_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH0_NP_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH0_NP_TX_DATA 0x13c ++#define ESPI_CH0_MCYC0_SADDRL 0x140 ++#define ESPI_CH0_MCYC0_SADDRH 0x144 ++#define ESPI_CH0_MCYC0_TADDRL 0x148 ++#define ESPI_CH0_MCYC0_TADDRH 0x14c ++#define ESPI_CH0_MCYC0_MASKL 0x150 ++#define ESPI_CH0_MCYC0_MASKL_EN BIT(0) ++#define ESPI_CH0_MCYC0_MASKH 0x154 ++#define ESPI_CH0_MCYC1_SADDRL 0x158 ++#define ESPI_CH0_MCYC1_SADDRH 0x15c ++#define ESPI_CH0_MCYC1_TADDRL 0x160 ++#define ESPI_CH0_MCYC1_TADDRH 0x164 ++#define ESPI_CH0_MCYC1_MASKL 0x168 ++#define ESPI_CH0_MCYC1_MASKL_EN BIT(0) ++#define ESPI_CH0_MCYC1_MASKH 0x16c ++#define ESPI_CH0_WPROT0 0x1f8 ++#define ESPI_CH0_WPROT1 0x1fc + -+ if (ioc->pkt_len < pkt_len) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; -+ } ++/* virtual wire channel (ch1) registers */ ++#define ESPI_CH1_CTRL 0x200 ++#define ESPI_CH1_CTRL_GPIO_HW BIT(9) ++#define ESPI_CH1_CTRL_SW_RDY BIT(1) ++#define ESPI_CH1_STS 0x204 ++#define ESPI_CH1_INT_STS 0x208 ++#define ESPI_CH1_INT_STS_GPIO BIT(1) ++#define ESPI_CH1_INT_STS_GPIO_CLR BIT(2) ++#define ESPI_CH1_INT_STS_EVT1 BIT(2) ++#define ESPI_CH1_INT_STS_EVT1_CLR BIT(1) ++#define ESPI_CH1_INT_STS_EVT0 BIT(0) ++#define ESPI_CH1_INT_EN 0x20c ++#define ESPI_CH1_INT_EN_GPIO BIT(1) ++#define ESPI_CH1_INT_EN_SYS_EVT1 BIT(2) ++#define ESPI_CH1_INT_EN_SYS_EVT0 BIT(0) ++#define ESPI_CH1_EVT0 0x210 ++#define ESPI_CH1_EVT0_PLTRSTN BIT(5) ++#define ESPI_CH1_EVT0_SCI_EVT BIT(24) ++#define ESPI_CH1_EVT0_INT_EN 0x214 ++#define ESPI_CH1_EVT0_INT_EN_PLTRSTN BIT(5) ++#define ESPI_CH1_EVT0_INT_T0 0x218 ++#define ESPI_CH1_EVT0_INT_T0_PLTRSTN BIT(5) ++#define ESPI_CH1_EVT0_INT_T1 0x21c ++#define ESPI_CH1_EVT0_INT_T1_PLTRSTN BIT(5) ++#define ESPI_CH1_EVT0_INT_T2 0x220 ++#define ESPI_CH1_EVT0_INT_T2_PLTRSTN BIT(5) ++#define ESPI_CH1_EVT0_INT_STS 0x224 ++#define ESPI_CH1_EVT0_INT_STS_PLTRSTN BIT(5) ++#define ESPI_CH1_EVT1 0x230 ++#define ESPI_CH1_EVT1_PCH_GENE GENMASK(15, 8) ++#define ESPI_CH1_EVT1_BMC_GENE GENMASK(31, 24) ++#define ESPI_CH1_EVT1_INT_EN 0x234 ++#define ESPI_CH1_EVT1_INT_EN_PCH_GENE GENMASK(15, 8) ++#define ESPI_CH1_EVT1_INT_T0 0x238 ++#define ESPI_CH1_EVT1_INT_T0_PCH_GENE GENMASK(15, 8) ++#define ESPI_CH1_EVT1_INT_T1 0x23c ++#define ESPI_CH1_EVT1_INT_T1_PCH_GENE GENMASK(15, 8) ++#define ESPI_CH1_EVT1_INT_T2 0x240 ++#define ESPI_CH1_EVT1_INT_T2_PCH_GENE GENMASK(15, 8) ++#define ESPI_CH1_EVT1_INT_STS 0x244 ++#define ESPI_CH1_EVT1_INT_STS_PCH_GENE GENMASK(15, 8) ++#define ESPI_CH1_GPIO_VAL0 0x250 ++#define ESPI_CH1_GPIO_VAL1 0x254 ++#define ESPI_CH1_GPIO_DIR0 0x258 ++#define ESPI_CH1_GPIO_DIR1 0x25c ++#define ESPI_CH1_GPIO_RSTSEL0 0x260 ++#define ESPI_CH1_GPIO_RSTSEL1 0x264 ++#define ESPI_CH1_GPIO_GRP 0x268 ++#define ESPI_CH1_GP50_DIR0 0x270 ++#define ESPI_CH1_GP50_DIR1 0x274 ++#define ESPI_CH1_GP50_VAL0 0x278 ++#define ESPI_CH1_GP50_VAL1 0x27c ++#define ESPI_CH1_SW_INT 0x280 ++#define ESPI_CH1_INT_RSTSEL0 0x284 ++#define ESPI_CH1_INT_RSTSEL1 0x288 ++#define ESPI_CH1_WPROT0 0x2f8 ++#define ESPI_CH1_WPROT1 0x2fc ++ ++/* out-of-band channel (ch2) registers */ ++#define ESPI_CH2_CTRL 0x300 ++#define ESPI_CH2_CTRL_TX_RST BIT(31) ++#define ESPI_CH2_CTRL_RX_RST BIT(30) ++#define ESPI_CH2_CTRL_TX_DMA_EN BIT(17) ++#define ESPI_CH2_CTRL_RX_DMA_EN BIT(16) ++#define ESPI_CH2_CTRL_SW_RDY BIT(4) ++#define ESPI_CH2_STS 0x304 ++#define ESPI_CH2_INT_STS 0x308 ++#define ESPI_CH2_INT_STS_RX_CMPLT BIT(0) ++#define ESPI_CH2_INT_EN 0x30c ++#define ESPI_CH2_INT_EN_RX_CMPLT BIT(0) ++#define ESPI_CH2_RX_DMAL 0x310 ++#define ESPI_CH2_RX_DMAH 0x314 ++#define ESPI_CH2_RX_CTRL 0x318 ++#define ESPI_CH2_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_CH2_RX_CTRL_PEC BIT(24) ++#define ESPI_CH2_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH2_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH2_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH2_RX_DATA 0x31c ++#define ESPI_CH2_TX_DMAL 0x320 ++#define ESPI_CH2_TX_DMAH 0x324 ++#define ESPI_CH2_TX_CTRL 0x328 ++#define ESPI_CH2_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_CH2_TX_CTRL_PEC BIT(24) ++#define ESPI_CH2_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH2_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH2_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH2_TX_DATA 0x32c ++#define ESPI_CH2_RX_DESC_EPTR 0x330 ++#define ESPI_CH2_RX_DESC_RPTR 0x334 ++#define ESPI_CH2_RX_DESC_RPTR_UPDATE BIT(31) ++#define ESPI_CH2_RX_DESC_RPTR_RP GENMASK(11, 0) ++#define ESPI_CH2_RX_DESC_WPTR 0x338 ++#define ESPI_CH2_RX_DESC_WPTR_VALID BIT(31) ++#define ESPI_CH2_RX_DESC_WPTR_SP GENMASK(27, 16) ++#define ESPI_CH2_RX_DESC_WPTR_WP GENMASK(11, 0) ++#define ESPI_CH2_RX_DESC_TMOUT 0x33c ++#define ESPI_CH2_TX_DESC_EPTR 0x340 ++#define ESPI_CH2_TX_DESC_RPTR 0x344 ++#define ESPI_CH2_TX_DESC_RPTR_UPT BIT(31) ++#define ESPI_CH2_TX_DESC_WPTR 0x348 ++#define ESPI_CH2_TX_DESC_WPTR_VALID BIT(31) ++#define ESPI_CH2_WPROT0 0x3f8 ++#define ESPI_CH2_WPROT1 0x3fc ++ ++/* flash channel (ch3) registers */ ++#define ESPI_CH3_CTRL 0x400 ++#define ESPI_CH3_CTRL_TX_RST BIT(31) ++#define ESPI_CH3_CTRL_RX_RST BIT(30) ++#define ESPI_CH3_CTRL_TX_DMA_EN BIT(17) ++#define ESPI_CH3_CTRL_RX_DMA_EN BIT(16) ++#define ESPI_CH3_CTRL_EDAF_MODE GENMASK(9, 8) ++#define ESPI_CH3_CTRL_SW_RDY BIT(5) ++#define ESPI_CH3_STS 0x404 ++#define ESPI_CH3_INT_STS 0x408 ++#define ESPI_CH3_INT_STS_RX_CMPLT BIT(0) ++#define ESPI_CH3_INT_EN 0x40c ++#define ESPI_CH3_INT_EN_RX_CMPLT BIT(0) ++#define ESPI_CH3_RX_DMAL 0x410 ++#define ESPI_CH3_RX_DMAH 0x414 ++#define ESPI_CH3_RX_CTRL 0x418 ++#define ESPI_CH3_RX_CTRL_SERV_PEND BIT(31) ++#define ESPI_CH3_RX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH3_RX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH3_RX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH3_RX_DATA 0x41c ++#define ESPI_CH3_TX_DMAL 0x420 ++#define ESPI_CH3_TX_DMAH 0x424 ++#define ESPI_CH3_TX_CTRL 0x428 ++#define ESPI_CH3_TX_CTRL_TRIG_PEND BIT(31) ++#define ESPI_CH3_TX_CTRL_LEN GENMASK(23, 12) ++#define ESPI_CH3_TX_CTRL_TAG GENMASK(11, 8) ++#define ESPI_CH3_TX_CTRL_CYC GENMASK(7, 0) ++#define ESPI_CH3_TX_DATA 0x42c ++#define ESPI_CH3_EDAF_TADDRL 0x430 ++#define ESPI_CH3_EDAF_TADDRH 0x434 ++#define ESPI_CH3_EDAF_MASKL 0x438 ++#define ESPI_CH3_EDAF_MASKH 0x43c ++#define ESPI_CH3_WPROT0 0x4f8 ++#define ESPI_CH3_WPROT1 0x4fc ++ ++/* eDAF filter registers */ ++#define ESPI_EDAF_FLTR_SADDR0 0x510 ++#define ESPI_EDAF_FLTR_EADDR0 0x514 ++#define ESPI_EDAF_FLTR_SADDR1 0x518 ++#define ESPI_EDAF_FLTR_EADDR1 0x51c ++#define ESPI_EDAF_FLTR_SADDR2 0x520 ++#define ESPI_EDAF_FLTR_EADDR2 0x524 ++#define ESPI_EDAF_FLTR_SADDR3 0x528 ++#define ESPI_EDAF_FLTR_EADDR3 0x52c ++#define ESPI_EDAF_FLTR_SADDR4 0x530 ++#define ESPI_EDAF_FLTR_EADDR4 0x534 ++#define ESPI_EDAF_FLTR_SADDR5 0x538 ++#define ESPI_EDAF_FLTR_EADDR5 0x53c ++#define ESPI_EDAF_FLTR_SADDR6 0x540 ++#define ESPI_EDAF_FLTR_EADDR6 0x544 ++#define ESPI_EDAF_FLTR_SADDR7 0x548 ++#define ESPI_EDAF_FLTR_EADDR7 0x54c ++#define ESPI_EDAF_FLTR_SADDR8 0x550 ++#define ESPI_EDAF_FLTR_EADDR8 0x554 ++#define ESPI_EDAF_FLTR_SADDR9 0x558 ++#define ESPI_EDAF_FLTR_EADDR9 0x55c ++#define ESPI_EDAF_FLTR_SADDR10 0x560 ++#define ESPI_EDAF_FLTR_EADDR10 0x564 ++#define ESPI_EDAF_FLTR_SADDR11 0x568 ++#define ESPI_EDAF_FLTR_EADDR11 0x56c ++#define ESPI_EDAF_FLTR_SADDR12 0x570 ++#define ESPI_EDAF_FLTR_EADDR12 0x574 ++#define ESPI_EDAF_FLTR_SADDR13 0x578 ++#define ESPI_EDAF_FLTR_EADDR13 0x57c ++#define ESPI_EDAF_FLTR_SADDR14 0x580 ++#define ESPI_EDAF_FLTR_EADDR14 0x584 ++#define ESPI_EDAF_FLTR_SADDR15 0x588 ++#define ESPI_EDAF_FLTR_EADDR15 0x58c ++#define ESPI_EDAF_WPROT0 0x5f8 ++#define ESPI_EDAF_WPROT1 0x5fc + -+ pkt = vmalloc(pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } ++void ast2700_espi_pre_init(struct aspeed_espi *espi); ++void ast2700_espi_post_init(struct aspeed_espi *espi); ++void ast2700_espi_deinit(struct aspeed_espi *espi); ++int ast2700_espi_perif_probe(struct aspeed_espi *espi); ++int ast2700_espi_perif_remove(struct aspeed_espi *espi); ++int ast2700_espi_vw_probe(struct aspeed_espi *espi); ++int ast2700_espi_vw_remove(struct aspeed_espi *espi); ++int ast2700_espi_oob_probe(struct aspeed_espi *espi); ++int ast2700_espi_oob_remove(struct aspeed_espi *espi); ++int ast2700_espi_flash_probe(struct aspeed_espi *espi); ++int ast2700_espi_flash_remove(struct aspeed_espi *espi); ++irqreturn_t ast2700_espi_isr(int irq, void *arg); + -+ hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = cyc; -+ hdr->tag = tag; -+ hdr->len_h = len >> 8; -+ hdr->len_l = len & 0xff; ++#endif +diff --git a/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.c b/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.c +--- a/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.c 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,1352 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) ASPEED Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ if (perif->dma.enable) { -+ memcpy(hdr + 1, perif->dma.pc_rx_virt, pkt_len - sizeof(*hdr)); -+ } else { -+ for (i = sizeof(*hdr); i < pkt_len; ++i) -+ reg = readl(espi->regs + ESPI_CH0_PC_RX_DATA) & 0xff; -+ } ++#include "ast2700-espi.h" ++#include "ast2700-intel-espi-mmbi.h" ++ ++#define HOST_READ_SCI_STATUS_BIT(x) ((x) & ESPI_CH1_EVT0_SCI_EVT) ++#define HOST_READ_RESET_REQ_BIT(x) ((x) & BIT(0)) ++#define HOST_READ_IF_UP_BIT(x) ((x) & BIT(1)) ++#define HOST_READ_RDY_BIT(x) ((x) & BIT(0)) ++#define HOST_READ_BUF_PTR(x) ((x) & GENMASK(31, 2)) ++ ++/* LPC register for SCI interrupt */ ++#define AST_LPC_SWCR0300 0x180 ++#define LPC_BMC_TRIG_WAKEUP_EVT_STS BIT(8) ++ ++#define AST_LPC_SWCR0704 0x184 ++#define LPC_BMC_TRIG_WAKEUP_EVT_EN BIT(8) ++ ++#define AST_LPC_SWCR0B08 0x188 ++#define LPC_BMC_TRIG_WAKEUP_EVT BIT(6) ++ ++#define AST_LPC_ACPIB3B0 0x1A8 ++#define LPC_BMC_TRIG_SCI_EVT_STS BIT(8) ++ ++#define AST_LPC_ACPIB7B4 0x1AC ++#define LPC_BMC_TRIG_SCI_EVT_EN BIT(8) ++ ++#define MMBI_SIGNATURE_STRING "#MMBI$" ++#define MMBI_BUF_TYPE_VPSCB_V1 0x01 /* Variable Packet Size Circular Buffer */ ++#define MMBI_MEMORY_SIZE SZ_64M ++#define MMBI_MAX_SUPPORT_PROTOCOLS 5 ++#define MMBI_HDR_LEN_MASK GENMASK(23, 2) ++#define MMBI_HDR_PADDING_MASK GENMASK(1, 0) ++#define MMBI_HDR_TYPE_MASK GENMASK(27, 24) ++#define AST2700_ESPI_MMBI_MAX_CHANNELS 8 ++ ++enum ast2700_espi_mmbi_state { /* B_U B_R H_U H_R */ ++ ESPI_MMBI_INIT_IN_PROGRESS = 0x00, /* 0 0 0 0 */ ++ ESPI_MMBI_INIT_COMPLETED = 0x08, /* 1 0 0 0 */ ++ ESPI_MMBI_NORMAL_RUNTIME = 0x0A, /* 1 0 1 0 */ ++ ESPI_MMBI_RESET_REQ_BY_BMC = 0x0E, /* 1 1 1 0 */ ++ ESPI_MMBI_RESET_REQ_BY_HOST = 0x0B, /* 1 0 1 1 */ ++ ESPI_MMBI_RESET_ACKED = 0x0F, /* 1 1 1 1 */ ++ ESPI_MMBI_TRANS_TO_INIT = 0x07, /* 0 1 1 1 */ ++ ESPI_MMBI_INIT_MISMATCH = 0x09, /* 1 0 0 1 */ ++ ESPI_MMBI_POWER_UP_OR_ERROR = 0x10, /* other states */ ++}; ++ ++// addresses below, if not specified, are all virtual addresses ++struct aspeed_mmbi_host_rws { ++ u32 host_rst_req: 1; ++ u32 host_if_up: 1; ++ u32 host_buf_wr_ptr: 30; /* Address that host should write data into */ ++ u32 host_rdy: 1; ++ u32 rsvd: 1; ++ u32 bmc_buf_rd_ptr: 30; /* Address that host should read data from */ ++}; ++ ++struct aspeed_mmbi_host_ros { ++ u32 bmc_rst_req: 1; ++ u32 bmc_if_up: 1; ++ u32 bmc_buf_wr_ptr: 30; /* Address that BMC should write data into */ ++ u32 bmc_rdy: 1; ++ u32 rsvd: 1; ++ u32 host_buf_rd_ptr: 30; /* Address that BMC should read data from */ ++}; ++ ++/* MMBI Variable Packet Size Circular Buffer(VPSCB) v1 descriptor ++ * memory addresses are all offset ++ */ ++struct aspeed_mmbi_vpscb_desc { ++ u32 host_ros_pointer; /* Host ROS Offset */ ++ u32 host_rws_pointer; /* Host RWS Offset */ ++ u8 host_int_type; /* how BMC interrupt host */ ++ u8 host_int_location; /* which channel BMC interrupt host given int_type */ ++ u8 rsvd1[3]; ++ u8 host_int_val; /* what BMC will write to interrupt host */ ++ u8 bmc_int_type; /* how host interrupt BMC */ ++ u32 bmc_int_location; /* which address host should write to interrupt BMC */ ++ u8 rsvd2[4]; ++ u8 bmc_int_val; /* what host will write to interrupt BMC */ ++} __packed; + -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++/* memory addresses are all physical */ ++struct aspeed_mmbi_desc { ++ u8 mmbi_signature[6]; ++ u8 mmbi_version; ++ u8 os_use; ++ u32 b2h_buf_base_addr; ++ u32 h2b_buf_base_addr; ++ u32 b2h_buf_len; ++ u32 h2b_buf_len; ++ u8 buf_type; ++ u8 rsvd1[7]; ++ struct aspeed_mmbi_vpscb_desc buf_desc; ++ u8 rsvd2[8]; ++}; + -+ spin_lock_irqsave(&perif->lock, flags); ++struct aspeed_mmbi_protocol_dev { ++ struct miscdevice miscdev; ++ struct aspeed_espi_mmbi_channel *channel; ++ u8 protocol_type; ++ bool data_available; ++ /* ++ * If user space application is opened for read, then only process ++ * the data and copy to userspace. Otherwise, discard the command and ++ * process the remaining commands (can be different protocol type) ++ */ ++ bool process_data; ++ wait_queue_head_t queue; ++}; + -+ writel(ESPI_CH0_PC_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH0_PC_RX_CTRL); -+ perif->rx_ready = 0; ++struct aspeed_espi_mmbi_channel { ++ u8 *desc; ++ u8 *host_ros; ++ u8 *host_rws; ++ u8 *b2h_circular_buf; ++ u32 b2h_circular_buf_size; ++ u8 *h2b_circular_buf; ++ u32 h2b_circular_buf_size; ++ struct ast2700_espi_mmbi *priv; + -+ spin_unlock_irqrestore(&perif->lock, flags); ++ struct aspeed_mmbi_protocol_dev protocols[MMBI_MAX_SUPPORT_PROTOCOLS]; + -+ rc = 0; ++ enum ast2700_espi_mmbi_state state; + -+free_n_out: -+ vfree(pkt); ++ bool enabled; ++ int chann_idx; ++}; + -+unlock_mtx_n_out: -+ mutex_unlock(&perif->pc_rx_mtx); ++struct ast2700_espi_mmbi { ++ struct regmap *mmbi_map; ++ struct regmap *espi_map; ++ struct regmap *lpc_map; ++ struct device *dev; ++ struct aspeed_espi_mmbi_channel channels[AST2700_ESPI_MMBI_MAX_CHANNELS]; ++ phys_addr_t host_map_addr; ++ dma_addr_t mmbi_phys_addr; ++ u8 *mmbi_virt_addr; ++ resource_size_t mmbi_size; ++ u32 mmbi_instances; ++}; + -+ return rc; -+} ++struct ast2700_espi_mmbi_hdr { ++ u32 data; ++}; + -+static long ast2700_espi_perif_pc_put_tx(struct file *fp, -+ struct ast2700_espi_perif *perif, -+ struct aspeed_espi_ioc *ioc) ++static void raise_sci_interrupt(struct aspeed_espi_mmbi_channel *channel) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint8_t *pkt; -+ int i, rc; -+ -+ espi = container_of(perif, struct ast2700_espi, perif); -+ -+ if (!mutex_trylock(&perif->pc_tx_mtx)) -+ return -EAGAIN; ++ u32 val; ++ int retry; ++ struct regmap *lpc_regmap = channel->priv->lpc_map; + -+ reg = readl(espi->regs + ESPI_CH0_PC_TX_CTRL); -+ if (reg & ESPI_CH0_PC_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_n_out; -+ } ++ dev_dbg(channel->priv->dev, "Raising SCI interrupt...\n"); + -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_n_out; -+ } ++ regmap_write_bits(lpc_regmap, AST_LPC_ACPIB7B4, LPC_BMC_TRIG_SCI_EVT_EN, ++ LPC_BMC_TRIG_SCI_EVT_EN); + -+ hdr = (struct espi_comm_hdr *)pkt; ++ regmap_write_bits(lpc_regmap, AST_LPC_SWCR0704, ++ LPC_BMC_TRIG_WAKEUP_EVT_EN, ++ LPC_BMC_TRIG_WAKEUP_EVT_EN); + -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++ regmap_write_bits(lpc_regmap, AST_LPC_SWCR0B08, LPC_BMC_TRIG_WAKEUP_EVT, ++ LPC_BMC_TRIG_WAKEUP_EVT); + + /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers ++ * Just asserting the SCI VW will trigger the SCI event continuosly. ++ * So BMC must deassert SCI VW to avoid it. ++ * ESPI098[24] reading will confirm Host read data or not. ++ * - 0 means host read the data ++ * - 1 means host not yet read data, so retry with 1us delay. + */ -+ if (perif->dma.enable) { -+ memcpy(perif->dma.pc_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); -+ dma_wmb(); -+ } else { -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_CH0_PC_TX_DATA); -+ } -+ -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -+ -+ reg = FIELD_PREP(ESPI_CH0_PC_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_CH0_PC_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_CH0_PC_TX_CTRL_LEN, len) -+ | ESPI_CH0_PC_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_CH0_PC_TX_CTRL); ++ retry = 30; ++ while (retry) { ++ if (regmap_read(channel->priv->espi_map, ESPI_CH1_EVT0, &val)) { ++ dev_err(channel->priv->dev, "Unable to read ESPI210\n"); ++ break; ++ } + -+ rc = 0; ++ if (HOST_READ_SCI_STATUS_BIT(val) == 0) ++ break; + -+free_n_out: -+ vfree(pkt); ++ retry--; ++ dev_dbg(channel->priv->dev, ++ "Host SCI handler not invoked(ESPI210: 0x%0x), so retry(%d) after 1us...\n", ++ val, retry); ++ udelay(1); ++ } + -+unlock_n_out: -+ mutex_unlock(&perif->pc_tx_mtx); ++ regmap_write_bits(lpc_regmap, AST_LPC_SWCR0300, ++ LPC_BMC_TRIG_WAKEUP_EVT_STS, ++ LPC_BMC_TRIG_WAKEUP_EVT_STS); + -+ return rc; ++ regmap_write_bits(lpc_regmap, AST_LPC_ACPIB3B0, ++ LPC_BMC_TRIG_SCI_EVT_STS, ++ LPC_BMC_TRIG_SCI_EVT_STS); +} + -+static long ast2700_espi_perif_np_put_tx(struct file *fp, -+ struct ast2700_espi_perif *perif, -+ struct aspeed_espi_ioc *ioc) ++static void raise_missing_sci(struct aspeed_espi_mmbi_channel *channel) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint8_t *pkt; -+ int i, rc; -+ -+ espi = container_of(perif, struct ast2700_espi, perif); -+ -+ if (!mutex_trylock(&perif->np_tx_mtx)) -+ return -EAGAIN; ++ int chan_idx; ++ u32 h_rwp1; ++ u32 b2h_rp, b2h_wp; ++ struct aspeed_mmbi_host_ros *h_ros_ptr; + -+ reg = readl(espi->regs + ESPI_CH0_NP_TX_CTRL); -+ if (reg & ESPI_CH0_NP_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_n_out; ++ chan_idx = channel->chann_idx; ++ if (regmap_read(channel->priv->mmbi_map, ESPI_MMBI_HOST_READ_RWP1(chan_idx), &h_rwp1)) { ++ dev_err(channel->priv->dev, "Failed to read Host RWP1\n"); ++ return; + } -+ -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_n_out; ++ if (!HOST_READ_RDY_BIT(h_rwp1)) { ++ // Host is not ready, no point in raising the SCI ++ return; + } + -+ hdr = (struct espi_comm_hdr *)pkt; -+ -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ b2h_wp = h_ros_ptr->bmc_buf_wr_ptr << 2; ++ b2h_rp = HOST_READ_BUF_PTR(h_rwp1); + -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ if (perif->dma.enable) { -+ memcpy(perif->dma.np_tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); -+ dma_wmb(); -+ } else { -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_CH0_NP_TX_DATA); ++ if (b2h_wp == b2h_rp) { ++ // Host has read all outstanding SCI data, ++ // Do not raise another SCI. ++ return; + } + -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -+ -+ reg = FIELD_PREP(ESPI_CH0_NP_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_CH0_NP_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_CH0_NP_TX_CTRL_LEN, len) -+ | ESPI_CH0_NP_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_CH0_NP_TX_CTRL); -+ -+ rc = 0; -+ -+free_n_out: -+ vfree(pkt); -+ -+unlock_n_out: -+ mutex_unlock(&perif->np_tx_mtx); -+ -+ return rc; ++ dev_dbg(channel->priv->dev, ++ "Host not read the data yet, so rising SCI interrupt again...\n"); ++ raise_sci_interrupt(channel); +} + -+static long ast2700_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static int ast2700_espi_mmbi_parse_hdr(struct aspeed_espi_mmbi_channel *channel, ++ u32 *data_length, u8 *type, ++ u32 *unread_data_len, u8 *padding) +{ -+ struct ast2700_espi_perif *perif; -+ struct aspeed_espi_ioc ioc; -+ -+ perif = container_of(fp->private_data, struct ast2700_espi_perif, mdev); -+ -+ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) -+ return -EFAULT; -+ -+ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) -+ return -EINVAL; ++ u32 h2b_rp, h2b_wp; ++ struct ast2700_espi_mmbi_hdr header; ++ struct aspeed_mmbi_host_ros *h_ros_ptr; ++ struct aspeed_mmbi_host_rws *h_rws_ptr; + -+ switch (cmd) { -+ case ASPEED_ESPI_PERIF_PC_GET_RX: -+ return ast2700_espi_perif_pc_get_rx(fp, perif, &ioc); -+ case ASPEED_ESPI_PERIF_PC_PUT_TX: -+ return ast2700_espi_perif_pc_put_tx(fp, perif, &ioc); -+ case ASPEED_ESPI_PERIF_NP_PUT_TX: -+ return ast2700_espi_perif_np_put_tx(fp, perif, &ioc); -+ default: -+ break; -+ }; ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ h_rws_ptr = (struct aspeed_mmbi_host_rws *)channel->host_rws; + -+ return -EINVAL; -+} ++ h2b_wp = h_rws_ptr->host_buf_wr_ptr << 2; ++ h2b_rp = h_ros_ptr->host_buf_rd_ptr << 2; + -+static int ast2700_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) -+{ -+ struct ast2700_espi_perif *perif; -+ unsigned long vm_size; -+ pgprot_t vm_prot; ++ if (h2b_wp >= h2b_rp) ++ *unread_data_len = h2b_wp - h2b_rp; ++ else ++ *unread_data_len = channel->h2b_circular_buf_size - h2b_rp + h2b_wp; + -+ perif = container_of(fp->private_data, struct ast2700_espi_perif, mdev); -+ if (!perif->mcyc.enable) -+ return -EPERM; ++ if (*unread_data_len < sizeof(struct ast2700_espi_mmbi_hdr)) { ++ dev_dbg(channel->priv->dev, "No data to read(%d -%d)\n", h2b_wp, ++ h2b_rp); ++ return -EAGAIN; ++ } + -+ vm_size = vma->vm_end - vma->vm_start; -+ vm_prot = vma->vm_page_prot; ++ dev_dbg(channel->priv->dev, "READ MMBI header from: 0x%0lx\n", ++ (ssize_t)(channel->h2b_circular_buf + h2b_rp)); + -+ if (((vma->vm_pgoff << PAGE_SHIFT) + vm_size) > perif->mcyc.size) -+ return -EINVAL; ++ if (h2b_rp + sizeof(struct ast2700_espi_mmbi_hdr) <= channel->h2b_circular_buf_size) { ++ memcpy_fromio((void *)&header, channel->h2b_circular_buf + h2b_rp, ++ sizeof(struct ast2700_espi_mmbi_hdr)); ++ } else { ++ ssize_t chunk_len = channel->h2b_circular_buf_size - h2b_rp; + -+ vm_prot = pgprot_noncached(vm_prot); ++ memcpy_fromio((void *)&header, channel->h2b_circular_buf + h2b_rp, ++ chunk_len); ++ memcpy_fromio(((u8 *)&header) + chunk_len, channel->h2b_circular_buf, ++ sizeof(struct ast2700_espi_mmbi_hdr) - chunk_len); ++ } + -+ if (remap_pfn_range(vma, vma->vm_start, -+ (perif->mcyc.taddr >> PAGE_SHIFT) + vma->vm_pgoff, -+ vm_size, vm_prot)) -+ return -EAGAIN; ++ *padding = FIELD_GET(MMBI_HDR_PADDING_MASK, header.data); ++ *data_length = FIELD_GET(MMBI_HDR_LEN_MASK, header.data) * 4 - *padding; ++ *type = FIELD_GET(MMBI_HDR_TYPE_MASK, header.data); + + return 0; +} + -+static const struct file_operations ast2700_espi_mmbi_b2h_fops = { -+ .owner = THIS_MODULE, -+ .mmap = ast2700_espi_mmbi_b2h_mmap, -+}; -+ -+static const struct file_operations ast2700_espi_mmbi_h2b_fops = { -+ .owner = THIS_MODULE, -+ .mmap = ast2700_espi_mmbi_h2b_mmap, -+ .poll = ast2700_espi_mmbi_h2b_poll, -+}; -+ -+static const struct file_operations ast2700_espi_perif_fops = { -+ .owner = THIS_MODULE, -+ .mmap = ast2700_espi_perif_mmap, -+ .unlocked_ioctl = ast2700_espi_perif_ioctl, -+}; -+ -+static irqreturn_t ast2700_espi_perif_mmbi_isr(int irq, void *arg) ++static void ast2700_espi_mmbi_update_host_ros(struct aspeed_espi_mmbi_channel *channel, ++ u32 read_len, u32 write_len) +{ -+ struct ast2700_espi_perif_mmbi *mmbi; -+ struct ast2700_espi_perif *perif; -+ struct ast2700_espi *espi; -+ uint32_t sts, tmp; -+ uint32_t *p; -+ int i; -+ -+ espi = (struct ast2700_espi *)arg; -+ -+ perif = &espi->perif; -+ -+ sts = readl(espi->regs + ESPI_MMBI_INT_STS); -+ if (!sts) -+ return IRQ_NONE; -+ -+ for (i = 0, tmp = sts; i < perif->mmbi.inst_num; ++i, tmp >>= 2) { -+ if (!(tmp & 0x3)) -+ continue; ++ struct aspeed_mmbi_host_ros *h_ros_ptr; ++ u32 rd_ptr, wr_ptr; + -+ mmbi = &perif->mmbi.inst[i]; ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ rd_ptr = h_ros_ptr->host_buf_rd_ptr << 2; ++ wr_ptr = h_ros_ptr->bmc_buf_wr_ptr << 2; + -+ p = (uint32_t *)mmbi->h2b_virt; -+ p[0] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i)); -+ p[1] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i) + 4); ++ /* Advance the B2H CB offset for next write */ ++ if ((wr_ptr + write_len) <= channel->b2h_circular_buf_size) ++ wr_ptr += write_len; ++ else ++ wr_ptr = wr_ptr + write_len - channel->b2h_circular_buf_size; + -+ mmbi->host_rwp_update = true; ++ /* Advance the H2B CB offset till where BMC read data */ ++ if ((rd_ptr + read_len) <= channel->h2b_circular_buf_size) ++ rd_ptr += read_len; ++ else ++ rd_ptr = rd_ptr + read_len - channel->h2b_circular_buf_size; + -+ wake_up_interruptible(&mmbi->wq); -+ } ++ h_ros_ptr->bmc_buf_wr_ptr = wr_ptr >> 2; ++ h_ros_ptr->host_buf_rd_ptr = rd_ptr >> 2; + -+ writel(sts, espi->regs + ESPI_MMBI_INT_STS); ++ dev_dbg(channel->priv->dev, "Updating HROS - h2b_rp: 0x%0x, b2h_wp: 0x%0x\n", ++ rd_ptr, wr_ptr); + -+ return IRQ_HANDLED; ++ if (write_len != 0) ++ raise_sci_interrupt(channel); +} + -+static void ast2700_espi_perif_isr(struct ast2700_espi *espi) ++static void ast2700_espi_mmbi_host_ifup_handler(struct aspeed_espi_mmbi_channel *channel) +{ -+ struct ast2700_espi_perif *perif; -+ unsigned long flags; -+ uint32_t sts; -+ -+ perif = &espi->perif; ++ struct aspeed_mmbi_host_ros *hros; + -+ sts = readl(espi->regs + ESPI_CH0_INT_STS); -+ -+ if (sts & ESPI_CH0_INT_STS_PC_RX_CMPLT) { -+ writel(ESPI_CH0_INT_STS_PC_RX_CMPLT, espi->regs + ESPI_CH0_INT_STS); -+ -+ spin_lock_irqsave(&perif->lock, flags); -+ perif->rx_ready = true; -+ spin_unlock_irqrestore(&perif->lock, flags); ++ dev_info(channel->priv->dev, ++ "Handle Host interface up request on MMBI channel(%d), state %d\n", ++ channel->chann_idx, channel->state); + -+ wake_up_interruptible(&perif->wq); ++ switch (channel->state) { ++ case ESPI_MMBI_INIT_COMPLETED: ++ hros = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ hros->bmc_rdy = 1; ++ channel->state = ESPI_MMBI_NORMAL_RUNTIME; ++ break; ++ default: ++ dev_err(channel->priv->dev, ++ "MMBI channel(%d) host state error\n", ++ channel->chann_idx); ++ channel->state = ESPI_MMBI_POWER_UP_OR_ERROR; ++ break; + } +} + -+static void ast2700_espi_perif_sw_reset(struct ast2700_espi *espi) ++static void ast2700_espi_mmbi_host_reset_handler(struct aspeed_espi_mmbi_channel *channel) +{ -+ struct device *dev; -+ uint32_t reg; -+ -+ dev = espi->dev; ++ dev_info(channel->priv->dev, ++ "Handle Host reset request on MMBI channel(%d), state %d\n", ++ channel->chann_idx, channel->state); + -+ reg = readl(espi->regs + ESPI_CH0_CTRL); -+ reg &= ~(ESPI_CH0_CTRL_NP_TX_RST -+ | ESPI_CH0_CTRL_NP_RX_RST -+ | ESPI_CH0_CTRL_PC_TX_RST -+ | ESPI_CH0_CTRL_PC_RX_RST -+ | ESPI_CH0_CTRL_NP_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_RX_DMA_EN -+ | ESPI_CH0_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); -+ -+ udelay(1); -+ -+ reg |= (ESPI_CH0_CTRL_NP_TX_RST -+ | ESPI_CH0_CTRL_NP_RX_RST -+ | ESPI_CH0_CTRL_PC_TX_RST -+ | ESPI_CH0_CTRL_PC_RX_RST); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ switch (channel->state) { ++ case ESPI_MMBI_INIT_COMPLETED: ++ memset(channel->host_ros, 0, sizeof(struct aspeed_mmbi_host_ros)); ++ dev_err(channel->priv->dev, ++ "Initialization mismatch on MMBI channel(%d)\n", ++ channel->chann_idx); ++ channel->state = ESPI_MMBI_INIT_MISMATCH; ++ break; ++ case ESPI_MMBI_NORMAL_RUNTIME: ++ /* Host requested for MMBI buffer reset */ ++ memset(channel->host_ros, 0, sizeof(struct aspeed_mmbi_host_ros)); ++ channel->state = ESPI_MMBI_INIT_IN_PROGRESS; ++ ++ dev_info(channel->priv->dev, ++ "Handle Host reset request on MMBI channel(%d)\n", ++ channel->chann_idx); ++ break; ++ default: ++ dev_err(channel->priv->dev, ++ "Invalid state(%d) on MMBI channel(%d) to handle Host reset request\n", ++ channel->state, channel->chann_idx); ++ channel->state = ESPI_MMBI_POWER_UP_OR_ERROR; ++ break; ++ } +} + -+static void ast2700_espi_perif_reset(struct ast2700_espi *espi) ++static void ast2700_espi_mmbi_host_write_handler(struct aspeed_espi_mmbi_channel *channel) +{ -+ struct ast2700_espi_perif *perif; -+ struct device *dev; -+ uint64_t mask; -+ uint32_t reg; -+ -+ dev = espi->dev; -+ -+ perif = &espi->perif; -+ -+ writel(0x0, espi->regs + ESPI_CH0_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_CH0_INT_STS); -+ -+ writel(0x0, espi->regs + ESPI_MMBI_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_MMBI_INT_STS); -+ -+ reg = readl(espi->regs + ESPI_CH0_CTRL); -+ reg &= ~(ESPI_CH0_CTRL_MCYC_RD_DIS_WDT | ESPI_CH0_CTRL_MCYC_WR_DIS_WDT); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); -+ -+ reg = readl(espi->regs + ESPI_CH0_MCYC0_MASKL); -+ reg &= ~ESPI_CH0_MCYC0_MASKL_EN; -+ writel(reg, espi->regs + ESPI_CH0_MCYC0_MASKL); -+ -+ reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL); -+ reg &= ~ESPI_CH0_MCYC1_MASKL_EN; -+ writel(reg, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ u32 data_length, unread_data_len; ++ u8 type, padding; ++ int rc, i; ++ bool handled = false; + -+ reg = readl(espi->regs + ESPI_CH0_CTRL); -+ reg |= (ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); -+ reg &= ~(ESPI_CH0_CTRL_NP_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_RX_DMA_EN -+ | ESPI_CH0_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ dev_info(channel->priv->dev, ++ "Handle Host write on MMBI channel(%d)\n", ++ channel->chann_idx); + -+ if (perif->mmbi.enable) { -+ reg = readl(espi->regs + ESPI_MMBI_CTRL); -+ reg &= ~ESPI_MMBI_CTRL_EN; -+ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ rc = ast2700_espi_mmbi_parse_hdr(channel, &data_length, &type, &unread_data_len, &padding); ++ if (rc) { ++ dev_dbg(channel->priv->dev, ++ "Failed to parse MMBI header on MMBI channel(%d)\n", ++ channel->chann_idx); ++ return; ++ } + -+ mask = ~(perif->mmbi.size - 1); -+ writel(mask >> 32, espi->regs + ESPI_CH0_MCYC0_MASKH); -+ writel(mask & 0xffffffff, espi->regs + ESPI_CH0_MCYC0_MASKL); -+ writel((perif->mmbi.saddr >> 32), espi->regs + ESPI_CH0_MCYC0_SADDRH); -+ writel((perif->mmbi.saddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC0_SADDRL); -+ writel((perif->mmbi.taddr >> 32), espi->regs + ESPI_CH0_MCYC0_TADDRH); -+ writel((perif->mmbi.taddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC0_TADDRL); ++ for (i = 0; i < MMBI_MAX_SUPPORT_PROTOCOLS; i++) { ++ if (channel->protocols[i].protocol_type == type) { ++ if (channel->protocols[i].process_data) { ++ handled = true; ++ channel->protocols[i].data_available = true; ++ wake_up_interruptible(&channel->protocols[i].queue); ++ } else { ++ ast2700_espi_mmbi_update_host_ros(channel, ++ data_length + ++ sizeof(struct ast2700_espi_mmbi_hdr) + ++ padding, ++ 0); ++ } ++ } ++ } + -+ writel((0x1 << (perif->mmbi.inst_num * 2)) - 1, espi->regs + ESPI_MMBI_INT_EN); ++ if (!handled) { ++ dev_warn(channel->priv->dev, ++ "No handler for protocol type %d on MMBI channel(%d), discard data\n", ++ type, channel->chann_idx); ++ ast2700_espi_mmbi_update_host_ros(channel, data_length + ++ sizeof(struct ast2700_espi_mmbi_hdr) + ++ padding, 0); ++ raise_sci_interrupt(channel); ++ } + -+ reg = FIELD_PREP(ESPI_MMBI_CTRL_INST_NUM, count_trailing_zeros(perif->mmbi.inst_num)) -+ | ESPI_MMBI_CTRL_EN; -+ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ dev_dbg(channel->priv->dev, "MMBI header parsed on MMBI channel(%d)\n", ++ channel->chann_idx); ++ dev_dbg(channel->priv->dev, "data len %d unread %d, type %d, padding %d\n", ++ data_length, unread_data_len, type, padding); ++} + -+ reg = readl(espi->regs + ESPI_CH0_MCYC0_MASKL) | ESPI_CH0_MCYC0_MASKL_EN; -+ writel(reg, espi->regs + ESPI_CH0_MCYC0_MASKL); ++static void ast2700_espi_mmbi_host_rwp0_handler(struct aspeed_espi_mmbi_channel *channel) ++{ ++ int chan_idx; ++ u32 h_rws_cur, h_rws_prev; + -+ reg = readl(espi->regs + ESPI_CH0_CTRL); -+ reg &= ~(ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ memcpy_fromio(&h_rws_prev, channel->host_rws, sizeof(h_rws_prev)); ++ chan_idx = channel->chann_idx; ++ if (regmap_read(channel->priv->mmbi_map, ESPI_MMBI_HOST_READ_RWP0(chan_idx), &h_rws_cur)) { ++ dev_err(channel->priv->dev, "Failed to read Host RWP0\n"); ++ return; + } + -+ if (perif->mcyc.enable) { -+ mask = ~(perif->mcyc.size - 1); -+ writel(mask >> 32, espi->regs + ESPI_CH0_MCYC1_MASKH); -+ writel(mask & 0xffffffff, espi->regs + ESPI_CH0_MCYC1_MASKL); -+ writel((perif->mcyc.saddr >> 32), espi->regs + ESPI_CH0_MCYC1_SADDRH); -+ writel((perif->mcyc.saddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC1_SADDRL); -+ writel((perif->mcyc.taddr >> 32), espi->regs + ESPI_CH0_MCYC1_TADDRH); -+ writel((perif->mcyc.taddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC1_TADDRL); -+ -+ reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL) | ESPI_CH0_MCYC1_MASKL_EN; -+ writel(reg, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ dev_dbg(channel->priv->dev, "Host RWP0 changed on MMBI channel(%d): 0x%08x -> 0x%08x\n", ++ channel->chann_idx, h_rws_prev, h_rws_cur); + -+ reg = readl(espi->regs + ESPI_CH0_CTRL); -+ reg &= ~(ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); -+ } ++ memcpy_fromio(channel->host_rws, &h_rws_cur, sizeof(h_rws_cur)); ++ if (HOST_READ_RESET_REQ_BIT(h_rws_cur) & ~HOST_READ_RESET_REQ_BIT(h_rws_prev)) ++ ast2700_espi_mmbi_host_reset_handler(channel); ++ else if (HOST_READ_IF_UP_BIT(h_rws_cur) & ~HOST_READ_IF_UP_BIT(h_rws_prev)) ++ ast2700_espi_mmbi_host_ifup_handler(channel); ++ else ++ ast2700_espi_mmbi_host_write_handler(channel); ++} + -+ if (perif->dma.enable) { -+ writel((perif->dma.np_tx_addr >> 32), espi->regs + ESPI_CH0_NP_TX_DMAH); -+ writel((perif->dma.np_tx_addr & 0xffffffff), espi->regs + ESPI_CH0_NP_TX_DMAL); -+ writel((perif->dma.pc_tx_addr >> 32), espi->regs + ESPI_CH0_PC_TX_DMAH); -+ writel((perif->dma.pc_tx_addr & 0xffffffff), espi->regs + ESPI_CH0_PC_TX_DMAL); -+ writel((perif->dma.pc_rx_addr >> 32), espi->regs + ESPI_CH0_PC_RX_DMAH); -+ writel((perif->dma.pc_rx_addr & 0xffffffff), espi->regs + ESPI_CH0_PC_RX_DMAL); ++static void ast2700_espi_mmbi_host_rwp1_handler(struct aspeed_espi_mmbi_channel *channel) ++{ ++ int chan_idx; ++ u32 h_rws_cur, h_rws_prev; + -+ reg = readl(espi->regs + ESPI_CH0_CTRL) -+ | ESPI_CH0_CTRL_NP_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CH0_CTRL); -+ } -+ if (perif->rtc_enable) { -+ reg = readl(espi->regs + ESPI_CAP_GEN) -+ | ESPI_CAP_GEN_RTC_SUP; -+ writel(reg, espi->regs + ESPI_CAP_GEN); ++ memcpy_fromio(&h_rws_prev, channel->host_rws + 4, sizeof(h_rws_prev)); ++ chan_idx = channel->chann_idx; ++ if (regmap_read(channel->priv->mmbi_map, ESPI_MMBI_HOST_READ_RWP1(chan_idx), &h_rws_cur)) { ++ dev_err(channel->priv->dev, "Failed to read Host RWP1\n"); ++ return; + } + -+ writel(ESPI_CH0_INT_EN_PC_RX_CMPLT, espi->regs + ESPI_CH0_INT_EN); ++ dev_dbg(channel->priv->dev, "Host RWP1 changed on MMBI channel(%d): 0x%08x -> 0x%08x\n", ++ channel->chann_idx, h_rws_prev, h_rws_cur); + -+ reg = readl(espi->regs + ESPI_CH0_CTRL) | ESPI_CH0_CTRL_SW_RDY; -+ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ memcpy_fromio(channel->host_rws + 4, &h_rws_cur, sizeof(h_rws_cur)); +} + -+static int ast2700_espi_perif_probe(struct ast2700_espi *espi) ++static void send_bmc_up_request(struct aspeed_espi_mmbi_channel *channel) +{ -+ struct ast2700_espi_perif_mmbi *mmbi; -+ struct ast2700_espi_perif *perif; -+ struct platform_device *pdev; -+ struct device_node *np; -+ struct resource res; -+ struct device *dev; -+ int i, rc; -+ -+ dev = espi->dev; ++ struct aspeed_mmbi_host_ros *hros; + -+ perif = &espi->perif; -+ -+ init_waitqueue_head(&perif->wq); ++ if (!channel->enabled || channel->state != ESPI_MMBI_INIT_IN_PROGRESS) { ++ dev_err(channel->priv->dev, ++ "Invalid state(%d) on MMBI channel(%d) to send BMC interface up request\n", ++ channel->state, channel->chann_idx); ++ return; ++ } + -+ spin_lock_init(&perif->lock); ++ hros = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ hros->bmc_if_up = 1; ++ channel->state = ESPI_MMBI_INIT_COMPLETED; + -+ mutex_init(&perif->np_tx_mtx); -+ mutex_init(&perif->pc_tx_mtx); -+ mutex_init(&perif->pc_rx_mtx); ++ dev_info(channel->priv->dev, ++ "Send BMC interface up request on MMBI channel(%d)\n", ++ channel->chann_idx); + -+ perif->mmbi.enable = of_property_read_bool(dev->of_node, "perif-mmbi-enable"); -+ if (perif->mmbi.enable) { -+ pdev = container_of(dev, struct platform_device, dev); ++ raise_sci_interrupt(channel); ++} + -+ perif->mmbi.irq = platform_get_irq(pdev, 1); -+ if (perif->mmbi.irq < 0) { -+ dev_err(dev, "cannot get MMBI IRQ number\n"); -+ return -ENODEV; -+ } ++static int send_bmc_reset_request(struct aspeed_espi_mmbi_channel *channel) ++{ ++ struct aspeed_mmbi_host_ros *hros; + -+ rc = of_property_read_u64(dev->of_node, "perif-mmbi-src-addr", &perif->mmbi.saddr); -+ if (rc || !IS_ALIGNED(perif->mmbi.saddr, PERIF_MMBI_ALIGN)) { -+ dev_err(dev, "cannot get 64MB-aligned MMBI host address\n"); -+ return -ENODEV; -+ } ++ hros = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ if (!channel->enabled) { ++ dev_err(channel->priv->dev, ++ "Invalid state(%d) on MMBI channel(%d) to send BMC reset request\n", ++ channel->enabled, channel->chann_idx); ++ return -EINVAL; ++ } ++ memset(channel->host_ros, 0, sizeof(struct aspeed_mmbi_host_ros)); ++ hros->bmc_rst_req = 1; ++ raise_sci_interrupt(channel); + -+ rc = of_property_read_u32(dev->of_node, "perif-mmbi-instance-num", &perif->mmbi.inst_num); -+ if (rc || -+ perif->mmbi.inst_num == 0 || -+ perif->mmbi.inst_num > PERIF_MMBI_MAX_INST || -+ (perif->mmbi.inst_num & (perif->mmbi.inst_num - 1))) { -+ dev_err(dev, "cannot get valid MMBI instance number, expect 1/2/4/8\n"); -+ return -EINVAL; -+ } ++ return 0; ++} + -+ np = of_parse_phandle(dev->of_node, "perif-mmbi-tgt-memory", 0); -+ if (!np || of_address_to_resource(np, 0, &res)) { -+ dev_err(dev, "cannot get MMBI memory region\n"); -+ return -ENODEV; -+ } ++static struct aspeed_mmbi_protocol_dev *file_aspeed_espi_mmbi(struct file *file) ++{ ++ return container_of(file->private_data, struct aspeed_mmbi_protocol_dev, ++ miscdev); ++} + -+ of_node_put(np); ++static int ast2700_espi_mmbi_open(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} + -+ perif->mmbi.taddr = res.start; -+ perif->mmbi.size = resource_size(&res); -+ perif->mmbi.inst_size = perif->mmbi.size / perif->mmbi.inst_num; -+ if (!IS_ALIGNED(perif->mmbi.taddr, PERIF_MMBI_ALIGN) || -+ !IS_ALIGNED(perif->mmbi.size, PERIF_MMBI_ALIGN)) { -+ dev_err(dev, "cannot get 64MB-aligned MMBI address/size\n"); -+ return -EINVAL; -+ } ++static int ast2700_espi_mmbi_release(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} + -+ perif->mmbi.virt = devm_ioremap_resource(dev, &res); -+ if (!perif->mmbi.virt) { -+ dev_err(dev, "cannot map MMBI memory region\n"); -+ return -ENOMEM; -+ } ++static unsigned int ast2700_espi_mmbi_poll(struct file *filp, poll_table *wait) ++{ ++ struct aspeed_mmbi_protocol_dev *protocol = file_aspeed_espi_mmbi(filp); + -+ memset_io(perif->mmbi.virt, 0, perif->mmbi.size); ++ poll_wait(filp, &protocol->queue, wait); + -+ for (i = 0; i < perif->mmbi.inst_num; ++i) { -+ mmbi = &perif->mmbi.inst[i]; ++ return protocol->data_available ? POLLIN : 0; ++} + -+ init_waitqueue_head(&mmbi->wq); ++static int get_mmbi_config(struct aspeed_espi_mmbi_channel *channel, void __user *userbuf) ++{ ++ struct aspeed_mmbi_host_ros *h_ros_ptr; ++ struct aspeed_mmbi_host_rws *h_rws_ptr; ++ struct aspeed_mmbi_get_config get_conf; + -+ mmbi->perif = perif; -+ mmbi->host_rwp_update = false; ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ h_rws_ptr = (struct aspeed_mmbi_host_rws *)channel->host_rws; + -+ mmbi->b2h_virt = perif->mmbi.virt + ((perif->mmbi.inst_size >> 1) * i); -+ mmbi->b2h_addr = perif->mmbi.taddr + ((perif->mmbi.inst_size >> 1) * i); -+ mmbi->b2h_mdev.parent = dev; -+ mmbi->b2h_mdev.minor = MISC_DYNAMIC_MINOR; -+ mmbi->b2h_mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-mmbi%d-b2h%d", -+ DEVICE_NAME, espi->dev_id, i); -+ mmbi->b2h_mdev.fops = &ast2700_espi_mmbi_b2h_fops; -+ rc = misc_register(&mmbi->b2h_mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", mmbi->b2h_mdev.name); -+ return rc; -+ } ++ get_conf.h_rdy = h_rws_ptr->host_rdy ? true : false; ++ get_conf.h2b_wp = h_rws_ptr->host_buf_wr_ptr << 2; ++ get_conf.b2h_rp = h_rws_ptr->bmc_buf_rd_ptr << 2; ++ get_conf.h2b_rp = h_ros_ptr->host_buf_rd_ptr << 2; ++ get_conf.b2h_wp = h_ros_ptr->bmc_buf_wr_ptr << 2; + -+ mmbi->h2b_virt = perif->mmbi.virt + ((perif->mmbi.inst_size >> 1) * (i + perif->mmbi.inst_num)); -+ mmbi->h2b_addr = perif->mmbi.taddr + ((perif->mmbi.inst_size >> 1) * (i + perif->mmbi.inst_num)); -+ mmbi->h2b_mdev.parent = dev; -+ mmbi->h2b_mdev.minor = MISC_DYNAMIC_MINOR; -+ mmbi->h2b_mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-mmbi%d-h2b%d", -+ DEVICE_NAME, espi->dev_id, i); -+ mmbi->h2b_mdev.fops = &ast2700_espi_mmbi_h2b_fops; -+ rc = misc_register(&mmbi->h2b_mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", mmbi->h2b_mdev.name); -+ return rc; -+ } -+ } ++ if (copy_to_user(userbuf, &get_conf, sizeof(get_conf))) { ++ dev_err(channel->priv->dev, "copy to user failed\n"); ++ return -EFAULT; + } ++ return 0; ++} + -+ perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); -+ if (perif->mcyc.enable) { -+ rc = of_property_read_u64(dev->of_node, "perif-mcyc-src-addr", &perif->mcyc.saddr); -+ if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { -+ dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); -+ return -ENODEV; -+ } -+ -+ rc = of_property_read_u64(dev->of_node, "perif-mcyc-size", &perif->mcyc.size); -+ if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { -+ dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); -+ return -EINVAL; -+ } -+ -+ np = of_parse_phandle(dev->of_node, "memory-region", 0); -+ if (np) { -+ of_reserved_mem_device_init(dev); -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "Failed to mask DMA.\n"); -+ return -ENODEV; -+ } -+ } ++static int get_b2h_empty_space(struct aspeed_espi_mmbi_channel *channel, ++ ssize_t *length) ++{ ++ struct aspeed_mmbi_host_ros *h_ros_ptr; ++ struct aspeed_mmbi_host_rws *h_rws_ptr; ++ ssize_t avail_buf_len; + -+ perif->mcyc.virt = dmam_alloc_coherent(dev, perif->mcyc.size, -+ &perif->mcyc.taddr, GFP_KERNEL); -+ if (!perif->mcyc.virt) { -+ dev_err(dev, "cannot allocate memory cycle\n"); -+ return -ENOMEM; -+ } -+ } ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ h_rws_ptr = (struct aspeed_mmbi_host_rws *)channel->host_rws; + -+ perif->dma.enable = of_property_read_bool(dev->of_node, "perif-dma-mode"); -+ if (perif->dma.enable) { -+ perif->dma.pc_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, -+ &perif->dma.pc_tx_addr, GFP_KERNEL); -+ if (!perif->dma.pc_tx_virt) { -+ dev_err(dev, "cannot allocate posted TX DMA buffer\n"); -+ return -ENOMEM; -+ } ++ if (h_ros_ptr->bmc_buf_wr_ptr >= h_rws_ptr->bmc_buf_rd_ptr) ++ avail_buf_len = channel->b2h_circular_buf_size - (h_ros_ptr->bmc_buf_wr_ptr << 2) + ++ (h_rws_ptr->bmc_buf_rd_ptr << 2); ++ else ++ avail_buf_len = (h_rws_ptr->bmc_buf_rd_ptr << 2) - (h_ros_ptr->bmc_buf_wr_ptr << 2); + -+ perif->dma.pc_rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, -+ &perif->dma.pc_rx_addr, GFP_KERNEL); -+ if (!perif->dma.pc_rx_virt) { -+ dev_err(dev, "cannot allocate posted RX DMA buffer\n"); -+ return -ENOMEM; -+ } ++ dev_dbg(channel->priv->dev, "B2H buffer empty space: %ld\n", avail_buf_len); + -+ perif->dma.np_tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, -+ &perif->dma.np_tx_addr, GFP_KERNEL); -+ if (!perif->dma.np_tx_virt) { -+ dev_err(dev, "cannot allocate non-posted TX DMA buffer\n"); -+ return -ENOMEM; -+ } -+ } -+ perif->rtc_enable = of_property_read_bool(dev->of_node, "perif-rtc-enable"); ++ *length = avail_buf_len; + -+ perif->mdev.parent = dev; -+ perif->mdev.minor = MISC_DYNAMIC_MINOR; -+ perif->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-peripheral%d", DEVICE_NAME, espi->dev_id); -+ perif->mdev.fops = &ast2700_espi_perif_fops; -+ rc = misc_register(&perif->mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", perif->mdev.name); -+ return rc; -+ } ++ return 0; ++} + -+ ast2700_espi_perif_reset(espi); ++static long ast2700_espi_mmbi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct aspeed_mmbi_protocol_dev *protocol = file_aspeed_espi_mmbi(filp); ++ struct aspeed_espi_mmbi_channel *channel = protocol->channel; ++ void __user *userbuf = (void __user *)arg; ++ ssize_t length; ++ int ret; + -+ if (perif->mmbi.enable) { -+ rc = devm_request_irq(dev, espi->perif.mmbi.irq, -+ ast2700_espi_perif_mmbi_isr, 0, dev_name(dev), espi); -+ if (rc) { -+ dev_err(dev, "cannot request MMBI IRQ\n"); -+ return rc; ++ switch (cmd) { ++ case ASPEED_MMBI_CTRL_IOCTL_GET_B2H_EMPTY_SPACE: ++ ret = get_b2h_empty_space(channel, &length); ++ if (ret == 0 && copy_to_user(userbuf, &length, sizeof(length))) { ++ dev_err(channel->priv->dev, "copy to user failed\n"); ++ ret = -EFAULT; + } ++ break; ++ ++ case ASPEED_MMBI_CTRL_IOCTL_SEND_RESET_REQUEST: ++ ret = send_bmc_reset_request(channel); ++ break; ++ ++ case ASPEED_MMBI_CTRL_IOCTL_GET_CONFIG: ++ ret = get_mmbi_config(channel, userbuf); ++ break; ++ ++ default: ++ dev_err(channel->priv->dev, "Command not found\n"); ++ ret = -ENOTTY; + } + -+ return 0; ++ return ret; +} + -+static int ast2700_espi_perif_remove(struct ast2700_espi *espi) ++static ssize_t ast2700_espi_mmbi_read(struct file *filp, char *buff, size_t count, ++ loff_t *offp) +{ -+ struct ast2700_espi_perif_mmbi *mmbi; -+ struct ast2700_espi_perif *perif; -+ struct device *dev; -+ uint32_t reg; -+ int i; ++ struct aspeed_mmbi_protocol_dev *protocol = file_aspeed_espi_mmbi(filp); ++ struct aspeed_espi_mmbi_channel *channel = protocol->channel; ++ struct ast2700_espi_mmbi *priv = channel->priv; ++ struct aspeed_mmbi_host_ros *h_ros_ptr; ++ u32 data_length, unread_data_len; ++ u32 buf_rd_offset; ++ u8 type, padding; ++ ssize_t rd_offset, rd_len; ++ ssize_t ret; + -+ dev = espi->dev; ++ protocol->process_data = true; ++ if (!protocol->data_available && (filp->f_flags & O_NONBLOCK)) { ++ raise_missing_sci(channel); ++ return -EAGAIN; ++ } + -+ perif = &espi->perif; ++ dev_dbg(priv->dev, "%s: count:%ld, Type: %d\n", __func__, count, ++ protocol->protocol_type); + -+ writel(0x0, espi->regs + ESPI_CH0_INT_EN); -+ writel(0x0, espi->regs + ESPI_MMBI_INT_EN); ++ ret = wait_event_interruptible(protocol->queue, protocol->data_available); ++ if (ret == -ERESTARTSYS) { ++ ret = -EINTR; ++ goto err_out; ++ } + -+ reg = readl(espi->regs + ESPI_CH0_MCYC0_MASKL); -+ reg &= ~ESPI_CH0_MCYC0_MASKL_EN; -+ writel(reg, espi->regs + ESPI_CH0_MCYC0_MASKL); ++ ret = ast2700_espi_mmbi_parse_hdr(channel, &data_length, &type, &unread_data_len, &padding); ++ if (ret) { ++ dev_err(priv->dev, "%s: Failed to parse MMBI header\n", __func__); ++ goto err_out; ++ } + -+ reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL); -+ reg &= ~ESPI_CH0_MCYC1_MASKL_EN; -+ writel(reg, espi->regs + ESPI_CH0_MCYC1_MASKL); ++ dev_dbg(priv->dev, "%s: PKT Length: %d, Type: %d, Unread Data Length: %d, Padding: %d\n", ++ __func__, data_length, type, unread_data_len, padding); + -+ reg = readl(espi->regs + ESPI_CH0_CTRL); -+ reg |= (ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); -+ reg &= ~(ESPI_CH0_CTRL_NP_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_TX_DMA_EN -+ | ESPI_CH0_CTRL_PC_RX_DMA_EN -+ | ESPI_CH0_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH0_CTRL); ++ if (data_length > count) { ++ dev_err(priv->dev, "%s: Buffer too small, need %d\n", __func__, ++ data_length); ++ ret = -EMSGSIZE; ++ /* discard this packet */ ++ ast2700_espi_mmbi_update_host_ros(channel, data_length + sizeof(struct ast2700_espi_mmbi_hdr) + padding, 0); ++ goto err_out; ++ } + -+ if (perif->mmbi.enable) { -+ reg = readl(espi->regs + ESPI_MMBI_CTRL); -+ reg &= ~ESPI_MMBI_CTRL_EN; -+ writel(reg, espi->regs + ESPI_MMBI_CTRL); ++ if (type != protocol->protocol_type) { ++ dev_err(priv->dev, "%s: Protocol type mismatch, expected %d\n", ++ __func__, protocol->protocol_type); ++ ret = -EPROTO; ++ goto err_out; ++ } + -+ for (i = 0; i < perif->mmbi.inst_num; ++i) { -+ mmbi = &perif->mmbi.inst[i]; -+ misc_deregister(&mmbi->b2h_mdev); -+ misc_deregister(&mmbi->h2b_mdev); -+ } ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ buf_rd_offset = h_ros_ptr->host_buf_rd_ptr << 2; ++ if (buf_rd_offset + sizeof(struct ast2700_espi_mmbi_hdr) <= channel->h2b_circular_buf_size) ++ rd_offset = buf_rd_offset + sizeof(struct ast2700_espi_mmbi_hdr); ++ else ++ rd_offset = (buf_rd_offset + sizeof(struct ast2700_espi_mmbi_hdr)) - channel->h2b_circular_buf_size; ++ ++ rd_len = data_length; + -+ devm_iounmap(dev, perif->mmbi.virt); ++ dev_dbg(priv->dev, "%s: Read from offset: 0x%0lx, length: %ld\n", ++ __func__, rd_offset, rd_len); ++ ++ if (unread_data_len < rd_len + sizeof(struct ast2700_espi_mmbi_hdr)) { ++ dev_err(priv->dev, "%s: Not enough data to read, need %ld\n", ++ __func__, rd_len + sizeof(struct ast2700_espi_mmbi_hdr)); ++ ret = -EAGAIN; ++ goto err_out; + } + -+ if (perif->mcyc.enable) -+ dmam_free_coherent(dev, perif->mcyc.size, perif->mcyc.virt, -+ perif->mcyc.taddr); ++ if ((channel->h2b_circular_buf_size - rd_offset) >= rd_len) { ++ if (copy_to_user(buff, channel->h2b_circular_buf + rd_offset, rd_len)) { ++ dev_err(priv->dev, "%s: copy to user failed\n", __func__); ++ ret = -EFAULT; ++ goto err_out; ++ } ++ } else { ++ ssize_t chunk_len = channel->h2b_circular_buf_size - rd_offset; + -+ if (perif->dma.enable) { -+ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.np_tx_virt, -+ perif->dma.np_tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_tx_virt, -+ perif->dma.pc_tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, perif->dma.pc_rx_virt, -+ perif->dma.pc_rx_addr); ++ if (copy_to_user(buff, channel->h2b_circular_buf + rd_offset, chunk_len) || ++ copy_to_user(buff + chunk_len, channel->h2b_circular_buf, ++ rd_len - chunk_len)) { ++ dev_err(priv->dev, "%s: copy to user failed\n", __func__); ++ ret = -EFAULT; ++ goto err_out; ++ } + } + -+ mutex_destroy(&perif->np_tx_mtx); -+ mutex_destroy(&perif->pc_tx_mtx); -+ mutex_destroy(&perif->pc_rx_mtx); ++ *offp += rd_len; ++ ret = rd_len; ++ ast2700_espi_mmbi_update_host_ros(channel, rd_len + sizeof(struct ast2700_espi_mmbi_hdr) + padding, 0); ++ dev_dbg(priv->dev, "%s: Read %ld bytes from MMBI\n", __func__, rd_len); ++err_out: ++ /* ++ * Raise the missing SCI's by checking pointer for host ++ * read acknowledgment. This will work around the Missing ++ * SCI bug on host side. * ++ */ ++ dev_warn(priv->dev, "%s: Check and raise missing SCI\n", __func__); ++ raise_missing_sci(channel); + -+ misc_deregister(&perif->mdev); ++ protocol->data_available = false; + -+ return 0; ++ ast2700_espi_mmbi_host_write_handler(channel); ++ ++ return ret; +} + -+/* virtual wire channel (CH1) */ -+static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static ssize_t ast2700_espi_mmbi_write(struct file *filp, const char *buffer, size_t len, ++ loff_t *offp) +{ -+ struct ast2700_espi_vw *vw; -+ struct ast2700_espi *espi; -+ uint32_t gpio0, gpio1; -+ uint32_t hw_mode; ++ struct aspeed_mmbi_protocol_dev *protocol = file_aspeed_espi_mmbi(filp); ++ struct aspeed_espi_mmbi_channel *channel = protocol->channel; ++ struct ast2700_espi_mmbi *priv = channel->priv; ++ struct aspeed_mmbi_host_rws *h_rws_ptr; ++ struct aspeed_mmbi_host_ros *h_ros_ptr; ++ struct ast2700_espi_mmbi_hdr header; + -+ vw = container_of(fp->private_data, struct ast2700_espi_vw, mdev); -+ espi = container_of(vw, struct ast2700_espi, vw); -+ gpio0 = vw->gpio.val0; -+ gpio1 = vw->gpio.val1; -+ hw_mode = vw->gpio.hw_mode; ++ ssize_t wr_offset, avail_buf_len, padding, chunk_len; + -+ if (hw_mode) { -+ dev_err(espi->dev, "HW mode: vGPIO reflect on physical GPIO. Get state from GPIO driver.\n"); -+ return -EFAULT; ++ h_rws_ptr = (struct aspeed_mmbi_host_rws *)channel->host_rws; ++ h_ros_ptr = (struct aspeed_mmbi_host_ros *)channel->host_ros; ++ ++ dev_dbg(priv->dev, "%s: length:%ld , type: %d\n", __func__, len, ++ protocol->protocol_type); ++ ++ if (!h_rws_ptr->host_if_up) { ++ dev_err(priv->dev, "%s: Host interface not up\n", __func__); ++ return -EAGAIN; + } + -+ switch (cmd) { -+ case ASPEED_ESPI_VW_GET_GPIO_VAL: -+ if (put_user(gpio0, (uint32_t __user *)arg)) { -+ dev_err(espi->dev, "failed to get vGPIO value0\n"); -+ return -EFAULT; -+ } ++ if (get_b2h_empty_space(channel, &avail_buf_len)) { ++ dev_err(priv->dev, "%s: Failed to get B2H empty space\n", __func__); ++ return -EFAULT; ++ } + -+ dev_info(espi->dev, "Get vGPIO value0: 0x%x\n", gpio0); -+ break; ++ if ((len + sizeof(struct ast2700_espi_mmbi_hdr)) > avail_buf_len) { ++ dev_err(priv->dev, "%s: No enough space in B2H buffer, need %ld but have %ld\n", ++ __func__, len + sizeof(struct ast2700_espi_mmbi_hdr), avail_buf_len); ++ return -ENOSPC; ++ } ++ padding = (4 - (len % 4)) % 4; ++ header.data = (protocol->protocol_type << 24) | (len & MMBI_HDR_LEN_MASK) | (padding & MMBI_HDR_PADDING_MASK); ++ wr_offset = h_ros_ptr->bmc_buf_wr_ptr << 2; + -+ case ASPEED_ESPI_VW_PUT_GPIO_VAL: -+ if (get_user(gpio0, (uint32_t __user *)arg)) { -+ dev_err(espi->dev, "failed to put vGPIO value0\n"); -+ return -EFAULT; -+ } ++ if (wr_offset + sizeof(struct ast2700_espi_mmbi_hdr) <= channel->b2h_circular_buf_size) { ++ memcpy_toio(channel->b2h_circular_buf + wr_offset, (void *)&header, ++ sizeof(struct ast2700_espi_mmbi_hdr)); ++ wr_offset += sizeof(struct ast2700_espi_mmbi_hdr); ++ if (wr_offset == channel->b2h_circular_buf_size) ++ wr_offset = 0; ++ } else { ++ chunk_len = channel->b2h_circular_buf_size - wr_offset; + -+ dev_info(espi->dev, "Put vGPIO value0: 0x%x\n", gpio0); -+ writel(gpio0, espi->regs + ESPI_CH1_GPIO_VAL0); -+ break; ++ memcpy_toio(channel->b2h_circular_buf + wr_offset, (void *)&header, ++ chunk_len); ++ memcpy_toio(channel->b2h_circular_buf, ((u8 *)&header) + chunk_len, ++ sizeof(struct ast2700_espi_mmbi_hdr) - chunk_len); ++ wr_offset = sizeof(struct ast2700_espi_mmbi_hdr) - chunk_len; ++ } + -+ case ASPEED_ESPI_VW_GET_GPIO_VAL1: -+ if (put_user(gpio1, (uint32_t __user *)arg)) { -+ dev_err(espi->dev, "failed to get vGPIO value1\n"); ++ if (wr_offset + len <= channel->b2h_circular_buf_size) { ++ if (copy_from_user(channel->b2h_circular_buf + wr_offset, buffer, len)) { ++ dev_err(priv->dev, "%s: copy from user failed\n", __func__); + return -EFAULT; + } ++ wr_offset += len; ++ if (wr_offset == channel->b2h_circular_buf_size) ++ wr_offset = 0; ++ } else { ++ chunk_len = channel->b2h_circular_buf_size - wr_offset; + -+ dev_info(espi->dev, "Get vGPIO value1: 0x%x\n", gpio1); -+ break; -+ -+ case ASPEED_ESPI_VW_PUT_GPIO_VAL1: -+ if (get_user(gpio1, (uint32_t __user *)arg)) { -+ dev_err(espi->dev, "failed to put vGPIO value1\n"); ++ if (copy_from_user(channel->b2h_circular_buf + wr_offset, buffer, chunk_len) || ++ copy_from_user(channel->b2h_circular_buf, ++ buffer + chunk_len, len - chunk_len)) { ++ dev_err(priv->dev, "%s: copy from user failed\n", __func__); + return -EFAULT; + } ++ wr_offset = len - chunk_len; ++ } + -+ dev_info(espi->dev, "Put vGPIO value1: 0x%x\n", gpio1); -+ writel(gpio1, espi->regs + ESPI_CH1_GPIO_VAL1); -+ break; -+ -+ default: -+ return -EINVAL; -+ }; ++ *offp += len; ++ ast2700_espi_mmbi_update_host_ros(channel, 0, len + sizeof(struct ast2700_espi_mmbi_hdr) + padding); ++ dev_dbg(priv->dev, "%s: Write %ld bytes to MMBI\n", __func__, len); + -+ return 0; ++ return len; +} + -+static const struct file_operations ast2700_espi_vw_fops = { ++static const struct file_operations ast2700_espi_mmbi_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2700_espi_vw_ioctl, ++ .open = ast2700_espi_mmbi_open, ++ .release = ast2700_espi_mmbi_release, ++ .read = ast2700_espi_mmbi_read, ++ .write = ast2700_espi_mmbi_write, ++ .unlocked_ioctl = ast2700_espi_mmbi_ioctl, ++ .poll = ast2700_espi_mmbi_poll +}; + -+static void ast2700_espi_vw_isr(struct ast2700_espi *espi) -+{ -+ struct ast2700_espi_vw *vw; -+ uint32_t sts; -+ -+ vw = &espi->vw; ++static const struct regmap_config aspeed_espi_mmbi_regmap_cfg = { ++ .name = "mmbi", ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = 0x04C, ++}; + -+ sts = readl(espi->regs + ESPI_CH1_INT_STS); ++static const struct regmap_config aspeed_espi_regmap_cfg = { ++ .name = "espi", ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = 0x7fc, ++}; + -+ if (sts & ESPI_CH1_INT_STS_GPIO) { -+ vw->gpio.val0 = readl(espi->regs + ESPI_CH1_GPIO_VAL0); -+ vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); -+ writel(ESPI_CH1_INT_STS_GPIO, espi->regs + ESPI_CH1_INT_STS); ++static const struct of_device_id aspeed_espi_mmbi_of_match[] = { ++ { .compatible = "aspeed,ast2700-intel-espi-mmbi" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_espi_mmbi_of_match); ++ ++static char *get_protocol_suffix(u8 type) ++{ ++ switch (type) { ++ case MMBI_PROTOCOL_IPMI: ++ return "ipmi"; ++ case MMBI_PROTOCOL_SEAMLESS: ++ return "seamless"; ++ case MMBI_PROTOCOL_RAS_OFFLOAD: ++ return "ras_offload"; ++ case MMBI_PROTOCOL_MCTP: ++ return "mctp"; ++ case MMBI_PROTOCOL_VENDOR: ++ return "vendor"; ++ default: ++ break; + } ++ ++ return NULL; +} + -+static void ast2700_espi_vw_reset(struct ast2700_espi *espi) ++static irqreturn_t ast2700_espi_mmbi_irq_handler(int irq, void *arg) +{ -+ uint32_t reg; -+ struct ast2700_espi_vw *vw = &espi->vw; ++ struct ast2700_espi_mmbi *priv = arg; ++ u32 status; ++ int idx; + -+ writel(0x0, espi->regs + ESPI_CH1_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_CH1_INT_STS); ++ regmap_read(priv->mmbi_map, ESPI_MMBI_INT_STATUS, &status); ++ /* Clear interrupt */ ++ regmap_write(priv->mmbi_map, ESPI_MMBI_INT_STATUS, status); + -+ writel(vw->gpio.grp, espi->regs + ESPI_CH1_GPIO_GRP); -+ writel(vw->gpio.dir0, espi->regs + ESPI_CH1_GPIO_DIR0); -+ writel(vw->gpio.dir1, espi->regs + ESPI_CH1_GPIO_DIR1); ++ for (idx = 0; idx < AST2700_ESPI_MMBI_MAX_CHANNELS; idx++) { ++ /* ++ * Host RWP 0: It gets updated after Host reads data and also ++ * when host want to send reset MMBI buffer request. So ++ * Handle reset request and ignore read pointer update. ++ * Host RWP 1: It gets updated when host write data on H2B, ++ * So process the request by invoking corresponding device. ++ */ ++ if (!priv->channels[idx].enabled) ++ continue; + -+ vw->gpio.val0 = readl(espi->regs + ESPI_CH1_GPIO_VAL0); -+ vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); ++ if ((status >> (idx * 2)) & ESPI_MMBI_HOST_RWS0_INT) { ++ // Host_RWS[0:3] update ++ ast2700_espi_mmbi_host_rwp0_handler(&priv->channels[idx]); ++ } else if (status >> (idx * 2) & ESPI_MMBI_HOST_RWS1_INT) { ++ // Host_RWS[4:7] update ++ ast2700_espi_mmbi_host_rwp1_handler(&priv->channels[idx]); ++ } ++ } ++ dev_info(priv->dev, "MMBI IRQ Status: %d\n", status); + -+ writel(ESPI_CH1_INT_EN_GPIO, espi->regs + ESPI_CH1_INT_EN); ++ return IRQ_HANDLED; ++} + -+ reg = readl(espi->regs + ESPI_CH1_CTRL) -+ | ((vw->gpio.hw_mode) ? ESPI_CH1_CTRL_GPIO_HW : 0) -+ | ESPI_CH1_CTRL_SW_RDY; -+ writel(reg, espi->regs + ESPI_CH1_CTRL); ++static void aspeed_espi_mmbi_release_rmem(void *d) ++{ ++ of_reserved_mem_device_release(d); ++} ++ ++static void aspeed_espi_mmbi_dma_finish(struct ast2700_espi_mmbi *priv) ++{ ++ dma_free_coherent(priv->dev, MMBI_MEMORY_SIZE, priv->mmbi_virt_addr, priv->mmbi_phys_addr); +} + -+static int ast2700_espi_vw_probe(struct ast2700_espi *espi) ++static int aspeed_espi_mmbi_dma_init(struct ast2700_espi_mmbi *priv) +{ + int rc; -+ struct device *dev = espi->dev; -+ struct ast2700_espi_vw *vw = &espi->vw; + -+ vw->gpio.hw_mode = of_property_read_bool(dev->of_node, "vw-gpio-hw-mode"); -+ of_property_read_u32(dev->of_node, "vw-gpio-group", &vw->gpio.grp); -+ of_property_read_u32_index(dev->of_node, "vw-gpio-direction", 0, &vw->gpio.dir0); -+ of_property_read_u32_index(dev->of_node, "vw-gpio-direction", 1, &vw->gpio.dir1); ++ rc = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ dev_err(priv->dev, "cannot set 64-bits DMA mask\n"); ++ return rc; ++ } + -+ vw->mdev.parent = dev; -+ vw->mdev.minor = MISC_DYNAMIC_MINOR; -+ vw->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-vw%d", DEVICE_NAME, espi->dev_id); -+ vw->mdev.fops = &ast2700_espi_vw_fops; -+ rc = misc_register(&vw->mdev); ++ /* DMA pool initialization */ ++ rc = of_reserved_mem_device_init(priv->dev); + if (rc) { -+ dev_err(dev, "cannot register device %s\n", vw->mdev.name); ++ dev_err(priv->dev, "device does not have specific DMA pool: %d\n", ++ rc); + return rc; + } + -+ ast2700_espi_vw_reset(espi); ++ rc = devm_add_action_or_reset(priv->dev, aspeed_espi_mmbi_release_rmem, ++ priv->dev); ++ if (rc) { ++ dev_err(priv->dev, "Failed to add action to release reserved memory: %d\n", ++ rc); ++ return rc; ++ } ++ ++ priv->mmbi_virt_addr = dma_alloc_coherent(priv->dev, MMBI_MEMORY_SIZE, ++ &priv->mmbi_phys_addr, GFP_KERNEL); ++ ++ if (!priv->mmbi_virt_addr) { ++ dev_err(priv->dev, "Failed to allocate DMA memory for MMBI\n"); ++ return -ENOMEM; ++ } ++ priv->mmbi_size = MMBI_MEMORY_SIZE; + + return 0; +} + -+static int ast2700_espi_vw_remove(struct ast2700_espi *espi) ++static int aspeed_espi_mmbi_hw_init(struct ast2700_espi_mmbi *priv) +{ -+ struct ast2700_espi_vw *vw; ++ u64 mask; ++ u32 reg; + -+ vw = &espi->vw; ++ /* disable interrupt and clear status */ ++ regmap_write(priv->espi_map, ESPI_CH0_INT_EN, 0x0); ++ regmap_write(priv->espi_map, ESPI_CH0_INT_STS, 0xffffffff); + -+ writel(0x0, espi->regs + ESPI_CH1_INT_EN); ++ regmap_write(priv->mmbi_map, ESPI_MMBI_INT_ENABLE, 0); ++ regmap_write(priv->mmbi_map, ESPI_MMBI_INT_STATUS, 0xffffffff); + -+ misc_deregister(&vw->mdev); ++ /* disable address masking, in here we use memory cycle 0 */ ++ regmap_read(priv->espi_map, ESPI_CH0_MCYC0_MASKL, ®); ++ reg &= ~ESPI_CH0_MCYC0_MASKL_EN; ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_MASKL, reg); ++ ++ regmap_read(priv->espi_map, ESPI_CH0_MCYC0_MASKL, ®); ++ reg &= ~ESPI_CH0_MCYC0_MASKL_EN; ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_MASKL, reg); ++ ++ /* disable memory w/r and clear eSPI CH0 queues */ ++ regmap_read(priv->espi_map, ESPI_CH0_CTRL, ®); ++ reg |= (ESPI_CH0_CTRL_MCYC_RD_DIS | ESPI_CH0_CTRL_MCYC_WR_DIS); ++ reg &= ~(ESPI_CH0_CTRL_NP_TX_RST ++ | ESPI_CH0_CTRL_NP_RX_RST ++ | ESPI_CH0_CTRL_PC_TX_RST ++ | ESPI_CH0_CTRL_PC_RX_RST ++ | ESPI_CH0_CTRL_NP_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_TX_DMA_EN ++ | ESPI_CH0_CTRL_PC_RX_DMA_EN ++ | ESPI_CH0_CTRL_SW_RDY); ++ regmap_write(priv->espi_map, ESPI_CH0_CTRL, reg); ++ ++ udelay(1); ++ ++ reg |= (ESPI_CH0_CTRL_NP_TX_RST ++ | ESPI_CH0_CTRL_NP_RX_RST ++ | ESPI_CH0_CTRL_PC_TX_RST ++ | ESPI_CH0_CTRL_PC_RX_RST); ++ regmap_write(priv->espi_map, ESPI_CH0_CTRL, reg); ++ ++ /* disable espi-mmbi controller before configuring espi address */ ++ regmap_read(priv->mmbi_map, ESPI_MMBI_CTRL, ®); ++ reg &= ~ESPI_MMBI_CTRL_EN; ++ regmap_write(priv->mmbi_map, ESPI_MMBI_CTRL, reg); ++ ++ mask = ~(priv->mmbi_size - 1); ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_MASKH, mask >> 32); ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_MASKL, mask & 0xffffffff); ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_SADDRH, priv->host_map_addr >> 32); ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_SADDRL, priv->host_map_addr & 0xffffffff); ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_TADDRH, priv->mmbi_phys_addr >> 32); ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_TADDRL, priv->mmbi_phys_addr & 0xffffffff); ++ ++ /* enable espi-mmbi controller and configure instances */ ++ reg = FIELD_PREP(ESPI_MMBI_CTRL_INST_NUM, ilog2(priv->mmbi_instances)) | ESPI_MMBI_CTRL_EN; ++ regmap_write(priv->mmbi_map, ESPI_MMBI_CTRL, reg); ++ ++ /* enable eSPI memory cycle 0 */ ++ regmap_read(priv->espi_map, ESPI_CH0_MCYC0_MASKL, ®); ++ reg |= ESPI_CH0_MCYC0_MASKL_EN; ++ regmap_write(priv->espi_map, ESPI_CH0_MCYC0_MASKL, reg); ++ ++ /* keep Peripheral Channel Mem Read/Write after WDT reset */ ++ regmap_read(priv->espi_map, ESPI_CH0_CTRL, ®); ++ reg &= ~(ESPI_CH0_CTRL_MCYC_RD_DIS_WDT | ESPI_CH0_CTRL_MCYC_WR_DIS_WDT); ++ regmap_write(priv->espi_map, ESPI_CH0_CTRL, reg); + + return 0; +} + -+/* out-of-band channel (CH2) */ -+static long ast2700_espi_oob_dma_get_rx(struct file *fp, -+ struct ast2700_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static struct aspeed_mmbi_desc aspeed_espi_mmbi_desc_init(struct aspeed_espi_mmbi_channel channel) +{ -+ struct ast2700_espi_oob_dma_rx_desc *d; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint32_t wptr, pkt_len; -+ unsigned long flags; -+ uint8_t *pkt; -+ int rc; -+ -+ espi = container_of(oob, struct ast2700_espi, oob); -+ -+ wptr = FIELD_PREP(ESPI_CH2_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_CH2_RX_DESC_WPTR)); ++ struct aspeed_mmbi_desc desc; + -+ d = &oob->dma.rxd_virt[wptr]; ++ memset(&desc, 0, sizeof(desc)); ++ memcpy_fromio(desc.mmbi_signature, MMBI_SIGNATURE_STRING, sizeof(desc.mmbi_signature)); ++ desc.mmbi_version = 1; ++ desc.os_use = 1; ++ desc.buf_type = MMBI_BUF_TYPE_VPSCB_V1; + -+ if (!d->dirty) -+ return -EFAULT; ++ desc.buf_desc.host_ros_pointer = (channel.host_ros - channel.desc) >> 3; ++ desc.buf_desc.host_rws_pointer = (channel.host_rws - channel.desc) >> 3; + -+ pkt_len = ((d->len) ? d->len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); ++ desc.buf_desc.host_int_type = 3; ++ desc.buf_desc.host_int_location = 0x06; ++ desc.buf_desc.host_int_val = 0x11; ++ desc.buf_desc.bmc_int_type = 0; ++ desc.buf_desc.bmc_int_location = 0x00; ++ desc.buf_desc.bmc_int_val = 0x00; + -+ if (ioc->pkt_len < pkt_len) -+ return -EINVAL; ++ desc.b2h_buf_base_addr = (u32)(channel.b2h_circular_buf - channel.desc) >> 3; ++ desc.h2b_buf_base_addr = (u32)(channel.h2b_circular_buf - channel.desc) >> 3; ++ desc.b2h_buf_len = channel.b2h_circular_buf_size; ++ desc.h2b_buf_len = channel.h2b_circular_buf_size; + -+ pkt = vmalloc(pkt_len); -+ if (!pkt) -+ return -ENOMEM; ++ return desc; ++} + -+ hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = d->cyc; -+ hdr->tag = d->tag; -+ hdr->len_h = d->len >> 8; -+ hdr->len_l = d->len & 0xff; -+ memcpy(hdr + 1, oob->dma.rx_virt + (PAGE_SIZE * wptr), pkt_len - sizeof(*hdr)); ++static int aspeed_espi_mmbi_chann_init(struct ast2700_espi_mmbi *priv, struct device_node *node, int seq, u8 idx) ++{ ++ struct aspeed_mmbi_desc desc; ++ int rc, i; ++ u8 protocol_num; ++ u8 protocol_supported[MMBI_MAX_SUPPORT_PROTOCOLS]; ++ u32 b2h_offset, h2b_offset; ++ u32 instance_size; ++ ++ memset(&priv->channels[idx], 0, sizeof(struct aspeed_espi_mmbi_channel)); ++ ++ /* configure virtual memory addresses ++ * In AST2700, memory layout is divided into B2H and H2B, ++ * B2H allocate top half and H2B allocate bottom half. ++ * For multiple instances, each instance is allocated separately in B2H and H2B. ++ * MMBI Capability Descriptor is at the top of B2H ++ */ ++ instance_size = MMBI_MEMORY_SIZE / 2 / priv->mmbi_instances; ++ b2h_offset = idx * instance_size; ++ h2b_offset = MMBI_MEMORY_SIZE / 2 + idx * instance_size; ++ ++ priv->channels[idx].desc = (u8 *)priv->mmbi_virt_addr + b2h_offset; ++ priv->channels[idx].host_ros = priv->channels[idx].desc + sizeof(struct aspeed_mmbi_desc); ++ priv->channels[idx].b2h_circular_buf = priv->channels[idx].host_ros + sizeof(struct aspeed_mmbi_host_ros); ++ priv->channels[idx].host_rws = (u8 *)priv->mmbi_virt_addr + h2b_offset; ++ priv->channels[idx].h2b_circular_buf = priv->channels[idx].host_rws + sizeof(struct aspeed_mmbi_host_rws); ++ ++ /* make sure buffer starts 4byte-aligned */ ++ priv->channels[idx].b2h_circular_buf = (u8 *)ALIGN((uintptr_t)priv->channels[idx].b2h_circular_buf, 4); ++ priv->channels[idx].h2b_circular_buf = (u8 *)ALIGN((uintptr_t)priv->channels[idx].h2b_circular_buf, 4); ++ ++ priv->channels[idx].b2h_circular_buf_size = instance_size - sizeof(struct aspeed_mmbi_desc) - ++ sizeof(struct aspeed_mmbi_host_ros); ++ priv->channels[idx].h2b_circular_buf_size = instance_size - sizeof(struct aspeed_mmbi_host_rws); ++ ++ memset(priv->channels[idx].host_ros, 0, sizeof(struct aspeed_mmbi_host_ros)); ++ memset(priv->channels[idx].host_rws, 0, sizeof(struct aspeed_mmbi_host_rws)); ++ priv->channels[idx].state = ESPI_MMBI_INIT_IN_PROGRESS; ++ ++ dev_dbg(priv->dev, "MMBI: Channel(%d) desc: 0x%llx, host_ros: 0x%llx, host_rws: 0x%llx\n", ++ idx, (unsigned long long)priv->channels[idx].desc, (unsigned long long)priv->channels[idx].host_ros, ++ (unsigned long long)priv->channels[idx].host_rws); ++ dev_dbg(priv->dev, "MMBI: Channel(%d) b2h_circular_buf: 0x%llx, h2b_circular_buf: 0x%llx\n", ++ idx, (unsigned long long)priv->channels[idx].b2h_circular_buf, ++ (unsigned long long)priv->channels[idx].h2b_circular_buf); ++ ++ desc = aspeed_espi_mmbi_desc_init(priv->channels[idx]); ++ memcpy_fromio(priv->channels[idx].desc, &desc, sizeof(desc)); ++ ++ priv->channels[idx].enabled = true; ++ priv->channels[idx].chann_idx = idx; ++ ++ if (!node) { ++ dev_err(priv->dev, "Fail to read instance"); ++ return -ENODEV; ++ } + -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; ++ protocol_num = of_property_count_u8_elems(node, "protocols"); ++ if (protocol_num < 0 || protocol_num > MMBI_MAX_SUPPORT_PROTOCOLS) { ++ dev_err(priv->dev, "Invalid number of protocols: %d\n", protocol_num); ++ return -EINVAL; + } + -+ spin_lock_irqsave(&oob->lock, flags); ++ rc = of_property_read_u8_array(node, "protocols", protocol_supported, protocol_num); ++ if (rc) { ++ dev_err(priv->dev, "Failed to read protocols for channel %d: %d\n", idx, rc); ++ return rc; ++ } + -+ /* make current descriptor available again */ -+ d->dirty = 0; ++ memset(priv->channels[idx].protocols, 0, sizeof(priv->channels[idx].protocols)); ++ for (i = 0; i < protocol_num; i++) { ++ u8 proto; ++ char *proto_name; + -+ wptr = ((wptr + 1) % OOB_DMA_DESC_NUM); -+ writel(wptr | ESPI_CH2_RX_DESC_WPTR_VALID, espi->regs + ESPI_CH2_RX_DESC_WPTR); ++ proto = protocol_supported[i]; ++ proto_name = get_protocol_suffix(proto); + -+ /* set ready flag base on the next RX descriptor */ -+ oob->rx_ready = oob->dma.rxd_virt[wptr].dirty; ++ if (!proto_name) { ++ dev_err(priv->dev, "Unsupported protocol type: %d\n", proto); ++ continue; ++ } + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ priv->channels[idx].protocols[i].miscdev.name = ++ devm_kasprintf(priv->dev, GFP_KERNEL, "%s%d-%s%d-%s", "espi-mmbi", seq, "chann", idx, proto_name); ++ priv->channels[idx].protocols[i].miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->channels[idx].protocols[i].miscdev.fops = &ast2700_espi_mmbi_fops; /* to be implemented */ ++ priv->channels[idx].protocols[i].miscdev.parent = priv->dev; ++ rc = misc_register(&priv->channels[idx].protocols[i].miscdev); ++ if (rc) { ++ dev_err(priv->dev, "Failed to register miscdev for protocol %s: %d\n", ++ proto_name, rc); ++ continue; ++ } ++ priv->channels[idx].protocols[i].protocol_type = proto; ++ priv->channels[idx].protocols[i].channel = &priv->channels[idx]; ++ priv->channels[idx].protocols[i].data_available = false; ++ priv->channels[idx].protocols[i].process_data = false; + -+ rc = 0; ++ init_waitqueue_head(&priv->channels[idx].protocols[i].queue); ++ } ++ priv->channels[idx].priv = priv; + -+free_n_out: -+ vfree(pkt); ++ dev_info(priv->dev, "MMBI: Channel(%d) protocols: %*ph\n", idx, ++ protocol_num, protocol_supported); + -+ return rc; ++ return 0; +} + -+static long ast2700_espi_oob_get_rx(struct file *fp, -+ struct ast2700_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static int aspeed_espi_mmbi_probe(struct platform_device *pdev) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; -+ int i, rc; ++ const struct of_device_id *dev_id; ++ struct ast2700_espi_mmbi *priv; ++ struct aspeed_espi *espi; ++ struct device_node *node; ++ void __iomem *regs; ++ int rc, seq, irq; ++ u32 i, mmbi_irq_en; + -+ espi = container_of(oob, struct ast2700_espi, oob); ++ dev_info(&pdev->dev, "ASPEED eSPI MMBI driver probe\n"); ++ if (!pdev->dev.parent) { ++ dev_err(&pdev->dev, "Device has no parent\n"); ++ return -ENODEV; ++ } + -+ if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&oob->rx_mtx)) -+ return -EAGAIN; ++ espi = dev_get_drvdata(pdev->dev.parent); ++ if (!espi) { ++ dev_err(&pdev->dev, "Failed to get eSPI controller data\n"); ++ return -EPROBE_DEFER; ++ } + -+ if (!oob->rx_ready) { -+ rc = -ENODATA; -+ goto unlock_mtx_n_out; -+ } -+ } else { -+ mutex_lock(&oob->rx_mtx); ++ dev_id = of_match_device(aspeed_espi_mmbi_of_match, &pdev->dev); ++ if (!dev_id) { ++ rc = PTR_ERR(dev_id); ++ goto out; ++ } + -+ if (!oob->rx_ready) { -+ rc = wait_event_interruptible(oob->wq, oob->rx_ready); -+ if (rc == -ERESTARTSYS) { -+ rc = -EINTR; -+ goto unlock_mtx_n_out; -+ } -+ } ++ priv = devm_kzalloc(&pdev->dev, sizeof(struct ast2700_espi_mmbi), GFP_KERNEL); ++ if (!priv) { ++ rc = -ENOMEM; ++ goto out; + } + -+ if (oob->dma.enable) { -+ rc = ast2700_espi_oob_dma_get_rx(fp, oob, ioc); -+ goto unlock_mtx_n_out; ++ priv->dev = &pdev->dev; ++ ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) { ++ rc = PTR_ERR(regs); ++ goto out; + } + -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ reg = readl(espi->regs + ESPI_CH2_RX_CTRL); -+ cyc = FIELD_GET(ESPI_CH2_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_CH2_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_CH2_RX_CTRL_LEN, reg); ++ /* MMBI register map */ ++ priv->mmbi_map = devm_regmap_init_mmio(&pdev->dev, regs, &aspeed_espi_mmbi_regmap_cfg); ++ if (IS_ERR(priv->mmbi_map)) { ++ rc = PTR_ERR(priv->mmbi_map); ++ goto out; ++ } + -+ /* -+ * calculate the length of the rest part of the -+ * eSPI packet to be read from HW and copied to -+ * user space. -+ */ -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); ++ /* ESPI register map */ ++ priv->espi_map = devm_regmap_init_mmio(priv->dev, espi->regs, ++ &aspeed_espi_regmap_cfg); ++ if (IS_ERR(priv->espi_map)) { ++ rc = PTR_ERR(priv->espi_map); ++ goto out; ++ } + -+ if (ioc->pkt_len < pkt_len) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; ++ /* LPC register map */ ++ priv->lpc_map = syscon_regmap_lookup_by_phandle(priv->dev->of_node, ++ "aspeed,lpc"); ++ if (IS_ERR(priv->lpc_map)) { ++ rc = PTR_ERR(priv->lpc_map); ++ goto out; + } + -+ pkt = vmalloc(pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; ++ rc = aspeed_espi_mmbi_dma_init(priv); ++ if (rc) ++ goto out_dma; ++ ++ rc = of_property_read_u64(priv->dev->of_node, "host-map-addr", &priv->host_map_addr); ++ if (rc) { ++ dev_err(priv->dev, "Failed to read host-map-addr property\n"); ++ goto out_dma; + } + -+ hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = cyc; -+ hdr->tag = tag; -+ hdr->len_h = len >> 8; -+ hdr->len_l = len & 0xff; ++ rc = of_property_read_u32(priv->dev->of_node, "instances", &priv->mmbi_instances); ++ if (rc) { ++ dev_err(priv->dev, "Failed to read mmbi instances property, set to 1\n"); ++ priv->mmbi_instances = 1; ++ } + -+ for (i = sizeof(*hdr); i < pkt_len; ++i) { -+ reg = readl(espi->regs + ESPI_CH2_RX_DATA); -+ pkt[i] = reg & 0xff; ++ /* check priv->mmbi_instances is less than 8 and is power of 2 */ ++ if (priv->mmbi_instances > 8 || !is_power_of_2(priv->mmbi_instances)) { ++ dev_err(priv->dev, "Invalid number of MMBI instances: %d\n", priv->mmbi_instances); ++ rc = -EINVAL; ++ goto out_dma; + } + -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; ++ dev_info(priv->dev, "MMBI: HostAddr:0x%llx, Physical addr:0x%llx, instances: %d\n", ++ priv->host_map_addr, priv->mmbi_phys_addr, priv->mmbi_instances); ++ ++ rc = aspeed_espi_mmbi_hw_init(priv); ++ if (rc) { ++ dev_err(priv->dev, "Failed to initialize MMBI hardware: %d\n", rc); ++ goto out_dma; + } + -+ spin_lock_irqsave(&oob->lock, flags); ++ seq = of_alias_get_id(priv->dev->of_node, "espi-mmbi"); ++ if (seq < 0) { ++ dev_err(priv->dev, "Failed to get device sequence id\n"); ++ seq = 0; ++ } + -+ writel(ESPI_CH2_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH2_RX_CTRL); -+ oob->rx_ready = 0; ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ rc = irq; ++ goto out_dma; ++ } + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ rc = devm_request_irq(priv->dev, irq, ast2700_espi_mmbi_irq_handler, IRQF_SHARED, ++ dev_name(priv->dev), priv); ++ if (rc) { ++ dev_err(priv->dev, "Failed to request IRQ: %d\n", rc); ++ goto out_dma; ++ } + -+ rc = 0; ++ mmbi_irq_en = 0; ++ for_each_child_of_node(priv->dev->of_node, node) { ++ rc = of_property_read_u32(node, "channel", &i); ++ if (rc || i >= AST2700_ESPI_MMBI_MAX_CHANNELS || priv->channels[i].enabled) ++ continue; ++ rc = aspeed_espi_mmbi_chann_init(priv, node, seq, i); ++ if (rc) ++ dev_err(priv->dev, "MMBI: Channel(%d) init failed\n", ++ i); ++ else ++ mmbi_irq_en += (0x03 << (i * 2)); ++ } + -+free_n_out: -+ vfree(pkt); ++ regmap_write(priv->mmbi_map, ESPI_MMBI_INT_ENABLE, mmbi_irq_en); + -+unlock_mtx_n_out: -+ mutex_unlock(&oob->rx_mtx); ++ for (i = 0; i < AST2700_ESPI_MMBI_MAX_CHANNELS; i++) { ++ if (priv->channels[i].enabled) ++ send_bmc_up_request(&priv->channels[i]); ++ } + ++ dev_set_drvdata(priv->dev, priv); ++ return 0; ++out_dma: ++ if (priv->mmbi_virt_addr) ++ aspeed_espi_mmbi_dma_finish(priv); ++out: ++ dev_err(&pdev->dev, "Failed to probe ASPEED eSPI MMBI: %d\n", rc); + return rc; +} + -+static long ast2700_espi_oob_dma_put_tx(struct file *fp, -+ struct ast2700_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static void aspeed_espi_mmbi_remove(struct platform_device *pdev) +{ -+ struct ast2700_espi_oob_dma_tx_desc *d; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint32_t rptr, wptr; -+ uint8_t *pkt; -+ int rc; ++ struct ast2700_espi_mmbi *priv = dev_get_drvdata(&pdev->dev); ++ u32 i, j, reg; + -+ espi = container_of(oob, struct ast2700_espi, oob); ++ if (!priv) ++ return; + -+ pkt = vzalloc(ioc->pkt_len); -+ if (!pkt) -+ return -ENOMEM; ++ regmap_write(priv->mmbi_map, ESPI_MMBI_INT_ENABLE, 0); + -+ hdr = (struct espi_comm_hdr *)pkt; ++ regmap_read(priv->mmbi_map, ESPI_MMBI_CTRL, ®); ++ reg &= ~ESPI_MMBI_CTRL_EN; ++ regmap_write(priv->mmbi_map, ESPI_MMBI_CTRL, reg); + -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; ++ for (i = 0; i < AST2700_ESPI_MMBI_MAX_CHANNELS; i++) { ++ if (!priv->channels[i].enabled) ++ continue; ++ ++ for (j = 0; j < MMBI_MAX_SUPPORT_PROTOCOLS; j++) { ++ if (!priv->channels[i].protocols[j].miscdev.this_device) ++ continue; ++ ++ misc_deregister(&priv->channels[i].protocols[j].miscdev); ++ } + } + -+ /* kick HW to update descriptor read/write pointer */ -+ writel(ESPI_CH2_TX_DESC_RPTR_UPT, espi->regs + ESPI_CH2_TX_DESC_RPTR); ++ if (priv->mmbi_virt_addr) ++ aspeed_espi_mmbi_dma_finish(priv); ++ ++ dev_info(&pdev->dev, "ASPEED eSPI MMBI driver removed\n"); ++} ++ ++static struct platform_driver aspeed_espi_mmbi_driver = { ++ .driver = { ++ .name = "ast2700-intel-espi-mmbi", ++ .of_match_table = aspeed_espi_mmbi_of_match, ++ }, ++ .probe = aspeed_espi_mmbi_probe, ++ .remove = aspeed_espi_mmbi_remove, ++}; ++ ++module_platform_driver(aspeed_espi_mmbi_driver); ++ ++MODULE_AUTHOR("Your Name "); ++MODULE_DESCRIPTION("ASPEED eSPI MMBI driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.h b/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.h +--- a/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2700-intel-espi-mmbi.h 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright 2025 Aspeed Technology Inc. ++ */ ++#ifndef _AST2700_ESPI_MMBI_H_ ++#define _AST2700_ESPI_MMBI_H_ ++ ++/* MMBI Control registers */ ++#define ESPI_MMBI_CTRL 0x00 ++#define ESPI_MMBI_CTRL_INST_NUM GENMASK(6, 4) ++#define ESPI_MMBI_CTRL_EN BIT(0) ++#define ESPI_MMBI_INT_STATUS 0x08 ++#define ESPI_MMBI_HOST_RWS0_INT BIT(0) ++#define ESPI_MMBI_HOST_RWS1_INT BIT(1) ++#define ESPI_MMBI_INT_ENABLE 0x0C ++ ++#define ESPI_MMBI_HOST_RWP0_VAL 0x10 ++#define ESPI_MMBI_HOST_RWP1_VAL 0x14 ++ ++#define ESPI_MMBI_HOST_READ_RWP0(idx) (((idx) * 8) + ESPI_MMBI_HOST_RWP0_VAL) ++#define ESPI_MMBI_HOST_READ_RWP1(idx) (((idx) * 8) + ESPI_MMBI_HOST_RWP1_VAL) ++ ++struct aspeed_mmbi_get_empty_space { ++ __u32 length; ++}; ++ ++struct aspeed_mmbi_get_config { ++ bool h_rdy; ++ __u32 h2b_wp; ++ __u32 b2h_rp; ++ __u32 h2b_rp; ++ __u32 b2h_wp; ++}; ++ ++#define __ASPEED_MMBI_CTRL_IOCTL_MAGIC 0xbb ++/* ++ * This IOCTL is meant to read empty space in B2H buffer ++ * in a specific channel ++ */ ++#define ASPEED_MMBI_CTRL_IOCTL_GET_B2H_EMPTY_SPACE \ ++ _IOWR(__ASPEED_MMBI_CTRL_IOCTL_MAGIC, 0x00, \ ++ struct aspeed_mmbi_get_empty_space) ++ ++/* This IOCTL to send BMC reset request */ ++#define ASPEED_MMBI_CTRL_IOCTL_SEND_RESET_REQUEST \ ++ _IOW(__ASPEED_MMBI_CTRL_IOCTL_MAGIC, 0x01, int) ++ ++/* This IOCTL is to Get Config in HROP and HRWP */ ++#define ASPEED_MMBI_CTRL_IOCTL_GET_CONFIG \ ++ _IOWR(__ASPEED_MMBI_CTRL_IOCTL_MAGIC, 0x02, \ ++ struct aspeed_mmbi_get_config) ++ ++#endif +diff --git a/drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c b/drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c +--- a/drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,193 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2025 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SYNC_INTERVAL_MS_DEFAULT 1000 ++ ++#define RTC_REG0 0x0 ++#define RTC_REG0_MINUTES_ALARM GENMASK(31, 24) ++#define RTC_REG0_MINUTES GENMASK(23, 16) ++#define RTC_REG0_SECONDS_ALARM GENMASK(15, 8) ++#define RTC_REG0_SECONDS GENMASK(7, 0) ++#define RTC_REG1 0x4 ++#define RTC_REG1_DAY_OF_MONTH GENMASK(31, 24) ++#define RTC_REG1_DAY_OF_WEEK GENMASK(23, 16) ++#define RTC_REG1_HOURS_ALARM GENMASK(15, 8) ++#define RTC_REG1_HOURS GENMASK(7, 0) ++#define RTC_REG2 0x8 ++#define RTC_REG2_YEAR GENMASK(15, 8) ++#define RTC_REG2_MONTH GENMASK(7, 0) ++#define RTC_REG_MAX 0xc ++ ++struct rtc_espi_sync { ++ struct rtc_device *rtc_dev; ++ struct device *dev; ++ void __iomem *espi_ram_base; ++ u32 interval_ms; ++ struct delayed_work sync_work; ++ struct workqueue_struct *wq; ++}; ++ ++static void sync_rtc_to_espi_work(struct work_struct *work) ++{ ++ struct rtc_espi_sync *ctx = container_of(to_delayed_work(work), struct rtc_espi_sync, sync_work); ++ struct rtc_time tm; ++ u32 reg, sec, min, hour, day_of_week, day_of_month, month, year; ++ u32 sec_alarm, min_alarm, hour_alarm; ++ int ret; + -+ rptr = readl(espi->regs + ESPI_CH2_TX_DESC_RPTR); -+ wptr = readl(espi->regs + ESPI_CH2_TX_DESC_WPTR); ++ if (!ctx->espi_ram_base) { ++ dev_err(ctx->dev, "eSPI RAM base not mapped\n"); ++ return; ++ } + -+ if (((wptr + 1) % OOB_DMA_DESC_NUM) == rptr) { -+ rc = -EBUSY; -+ goto free_n_out; ++ ret = rtc_read_time(ctx->rtc_dev, &tm); ++ if (ret < 0) { ++ dev_err(ctx->dev, "Failed to read RTC time: %d\n", ret); ++ goto reschedule; + } ++ dev_dbg(ctx->dev, "%s: tm data: secs=%d, mins=%d, hours=%d, mon=%d, year=%d\n", ++ __func__, tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_year); ++ dev_dbg(ctx->dev, "%s: tm data: wday(day of week)=%d, mday(day of month)=%d\n", ++ __func__, tm.tm_wday, tm.tm_mday); + -+ d = &oob->dma.txd_virt[wptr]; -+ d->cyc = hdr->cyc; -+ d->tag = hdr->tag; -+ d->len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -+ d->msg_type = OOB_DMA_DESC_CUSTOM; ++ /* Write the eSPI RAM registers */ ++ reg = FIELD_PREP(RTC_REG0_SECONDS, tm.tm_sec) | ++ FIELD_PREP(RTC_REG0_MINUTES, tm.tm_min); ++ writel(reg, (ctx->espi_ram_base + RTC_REG0)); + -+ memcpy(oob->dma.tx_virt + (PAGE_SIZE * wptr), hdr + 1, ioc->pkt_len - sizeof(*hdr)); ++ reg = FIELD_PREP(RTC_REG1_HOURS, tm.tm_hour) | ++ FIELD_PREP(RTC_REG1_DAY_OF_MONTH, tm.tm_mday) | ++ FIELD_PREP(RTC_REG1_DAY_OF_WEEK, tm.tm_wday + 1); ++ writel(reg, ctx->espi_ram_base + RTC_REG1); + -+ dma_wmb(); ++ reg = FIELD_PREP(RTC_REG2_MONTH, tm.tm_mon + 1) | ++ FIELD_PREP(RTC_REG2_YEAR, tm.tm_year % 100); ++ writel(reg, ctx->espi_ram_base + RTC_REG2); + -+ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; -+ writel(wptr | ESPI_CH2_TX_DESC_WPTR_VALID, espi->regs + ESPI_CH2_TX_DESC_WPTR); ++ /* Read back the values to verify */ ++ reg = readl(ctx->espi_ram_base + RTC_REG0); ++ sec = FIELD_GET(RTC_REG0_SECONDS, reg); ++ sec_alarm = FIELD_GET(RTC_REG0_SECONDS_ALARM, reg); ++ min = FIELD_GET(RTC_REG0_MINUTES, reg); ++ min_alarm = FIELD_GET(RTC_REG0_MINUTES_ALARM, reg); + -+ rc = 0; ++ reg = readl(ctx->espi_ram_base + RTC_REG1); ++ hour = FIELD_GET(RTC_REG1_HOURS, reg); ++ hour_alarm = FIELD_GET(RTC_REG1_HOURS_ALARM, reg); ++ day_of_week = FIELD_GET(RTC_REG1_DAY_OF_WEEK, reg); ++ day_of_month = FIELD_GET(RTC_REG1_DAY_OF_MONTH, reg); + -+free_n_out: -+ vfree(pkt); ++ reg = readl(ctx->espi_ram_base + RTC_REG2); ++ month = FIELD_GET(RTC_REG2_MONTH, reg); ++ year = FIELD_GET(RTC_REG2_YEAR, reg); + -+ return rc; ++ dev_dbg(ctx->dev, "%s: eSPI RAM data: secs=%d, mins=%d, hours=%d, ", ++ __func__, sec, min, hour); ++ dev_dbg(ctx->dev, "day_of_week=%d, day_of_month=%d, month=%d, year=%d\n", ++ day_of_week, day_of_month, month, year); ++ dev_dbg(ctx->dev, "%s: eSPI RAM data: secs_alarm=%d, mins_alarm=%d, hours_alarm=%d\n", ++ __func__, sec_alarm, min_alarm, hour_alarm); ++ ++reschedule: ++ queue_delayed_work(ctx->wq, &ctx->sync_work, msecs_to_jiffies(ctx->interval_ms)); +} + -+static long ast2700_espi_oob_put_tx(struct file *fp, -+ struct ast2700_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static int rtc_espi_sync_probe(struct platform_device *pdev) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint8_t *pkt; -+ int i, rc; -+ -+ espi = container_of(oob, struct ast2700_espi, oob); ++ struct device *dev = &pdev->dev; ++ struct rtc_espi_sync *ctx; ++ struct device_node *np = dev->of_node; ++ struct rtc_device *rtc; ++ struct resource *res; ++ u32 interval = SYNC_INTERVAL_MS_DEFAULT; + -+ if (!mutex_trylock(&oob->tx_mtx)) -+ return -EAGAIN; ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; + -+ if (oob->dma.enable) { -+ rc = ast2700_espi_oob_dma_put_tx(fp, oob, ioc); -+ goto unlock_mtx_n_out; ++ /* Ensure the device tree node is valid */ ++ rtc = rtc_class_open("rtc0"); ++ if (!rtc) { ++ dev_info(dev, "RTC not ready, deferring probe\n"); ++ return -EPROBE_DEFER; + } + -+ reg = readl(espi->regs + ESPI_CH2_TX_CTRL); -+ if (reg & ESPI_CH2_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_mtx_n_out; ++ /* Check if the RTC device supports the read_time operation */ ++ if (!rtc->ops || !rtc->ops->read_time) { ++ dev_err(dev, "RTC device does not support read_time operation\n"); ++ rtc_class_close(rtc); ++ return -ENODEV; + } + -+ if (ioc->pkt_len > ESPI_MAX_PKT_LEN) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; -+ } ++ ctx->rtc_dev = rtc; ++ ctx->dev = dev; + -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } ++ /* Get eSPI RAM handle and map */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ctx->espi_ram_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(ctx->espi_ram_base)) ++ return PTR_ERR(ctx->espi_ram_base); + -+ hdr = (struct espi_comm_hdr *)pkt; ++ if (!ctx->espi_ram_base) ++ memset(ctx->espi_ram_base, 0, RTC_REG_MAX); + -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++ /* Optional: polling interval */ ++ of_property_read_u32(np, "interval-ms", &interval); ++ ctx->interval_ms = interval; + -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_CH2_TX_DATA); ++ ctx->wq = alloc_workqueue("rtc_espi_sync_wq", WQ_UNBOUND, 0); ++ if (!ctx->wq) ++ return -ENOMEM; + -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ INIT_DELAYED_WORK(&ctx->sync_work, sync_rtc_to_espi_work); ++ queue_delayed_work(ctx->wq, &ctx->sync_work, 0); + -+ reg = FIELD_PREP(ESPI_CH2_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_CH2_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_CH2_TX_CTRL_LEN, len) -+ | ESPI_CH2_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_CH2_TX_CTRL); ++ dev_info(dev, "RTC-eSPI RAM sync initialized, every %u ms\n", ctx->interval_ms); + -+ rc = 0; ++ platform_set_drvdata(pdev, ctx); ++ return 0; ++} + -+free_n_out: -+ vfree(pkt); ++static void rtc_espi_sync_remove(struct platform_device *pdev) ++{ ++ struct rtc_espi_sync *ctx = platform_get_drvdata(pdev); + -+unlock_mtx_n_out: -+ mutex_unlock(&oob->tx_mtx); ++ cancel_delayed_work_sync(&ctx->sync_work); ++ destroy_workqueue(ctx->wq); + -+ return rc; ++ if (ctx->rtc_dev) ++ rtc_class_close(ctx->rtc_dev); +} + -+static long ast2700_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -+{ -+ struct ast2700_espi_oob *oob; -+ struct aspeed_espi_ioc ioc; ++static const struct of_device_id rtc_espi_sync_of_match[] = { ++ { .compatible = "aspeed,ast2700-rtc-over-espi" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, rtc_espi_sync_of_match); + -+ oob = container_of(fp->private_data, struct ast2700_espi_oob, mdev); ++static struct platform_driver rtc_espi_sync_driver = { ++ .driver = { ++ .name = "ast2700-rtc-over-espi", ++ .of_match_table = rtc_espi_sync_of_match, ++ }, ++ .probe = rtc_espi_sync_probe, ++ .remove = rtc_espi_sync_remove, ++}; ++module_platform_driver(rtc_espi_sync_driver); + -+ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) -+ return -EFAULT; ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Kevin Chen "); ++MODULE_DESCRIPTION("RTC to eSPI RAM sync driver"); +diff --git a/drivers/soc/aspeed/mmbi/Kconfig b/drivers/soc/aspeed/mmbi/Kconfig +--- a/drivers/soc/aspeed/mmbi/Kconfig 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/Kconfig 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,17 @@ ++menu "ASPEED MMBI driver" ++ ++config ASPEED_MMBI ++ tristate "ASPEED MMBI driver" ++ help ++ Enable support for the ASPEED MMBI driver. This driver ++ provides a communication channel between the Host and the BMC ++ over PCIe using the MMBI (Memory Mapped Buffer Interface). + -+ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) -+ return -EINVAL; ++config ASPEED_PCIE_MMBI ++ tristate "ASPEED PCIE MMBI" ++ depends on ASPEED_MMBI + -+ switch (cmd) { -+ case ASPEED_ESPI_OOB_GET_RX: -+ return ast2700_espi_oob_get_rx(fp, oob, &ioc); -+ case ASPEED_ESPI_OOB_PUT_TX: -+ return ast2700_espi_oob_put_tx(fp, oob, &ioc); -+ }; ++config ASPEED_HOST_PCIE_MMBI ++ tristate "ASPEED Host PCIE MMBI" + -+ return -EINVAL; -+} ++endmenu +diff --git a/drivers/soc/aspeed/mmbi/Makefile b/drivers/soc/aspeed/mmbi/Makefile +--- a/drivers/soc/aspeed/mmbi/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/Makefile 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_ASPEED_MMBI) += aspeed-mmbi.o aspeed-mmbi-bmc.o aspeed-mmbi-host.o ++obj-$(CONFIG_ASPEED_PCIE_MMBI) += aspeed-pcie-mmbi.o ++obj-$(CONFIG_ASPEED_HOST_PCIE_MMBI) += aspeed-host-pcie-mmbi.o +diff --git a/drivers/soc/aspeed/mmbi/aspeed-host-pcie-mmbi.c b/drivers/soc/aspeed/mmbi/aspeed-host-pcie-mmbi.c +--- a/drivers/soc/aspeed/mmbi/aspeed-host-pcie-mmbi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-host-pcie-mmbi.c 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,287 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Implements PCIe Transport in host side for MMBI protocol ++ * Copyright 2026 Aspeed Technology Inc. ++ */ + -+static const struct file_operations ast2700_espi_oob_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2700_espi_oob_ioctl, -+}; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+static void ast2700_espi_oob_isr(struct ast2700_espi *espi) -+{ -+ struct ast2700_espi_oob *oob; -+ unsigned long flags; -+ uint32_t sts; ++#include "aspeed-mmbi.h" + -+ oob = &espi->oob; ++#define DRIVER_NAME "aspeed-host-pcie-mmbi" ++#define MAX_MSI_NUM 32 ++/* Value for triggering interrupt */ ++#define ASPEED_E2M_INT_VAL 0xC6 + -+ sts = readl(espi->regs + ESPI_CH2_INT_STS); ++struct aspeed_host_pcie_mmbi_ins { ++ struct mmbi_ins_desc mmbi_desc; ++ int irq; ++ int msi_index; ++ int instance_index; ++ int bar_index; ++ const char *dev_name; ++ bool valid; ++}; + -+ if (sts & ESPI_CH2_INT_STS_RX_CMPLT) { -+ writel(ESPI_CH2_INT_STS_RX_CMPLT, espi->regs + ESPI_CH2_INT_STS); ++struct aspeed_host_pcie_mmbi { ++ struct device *dev; ++ struct aspeed_host_pcie_mmbi_ins instances[PCI_STD_NUM_BARS]; ++ int msi_nums; ++}; + -+ spin_lock_irqsave(&oob->lock, flags); -+ oob->rx_ready = true; -+ spin_unlock_irqrestore(&oob->lock, flags); ++/* ++ * app_interface: per-channel application interface selection. ++ * 0 = ioctl (MMBI_APP_INTF_IOCTL) ++ * 1 = mctp-netdev (MMBI_APP_INTF_MCTP_NETDEV) ++ * ++ * One value applies to every channel. Multiple values map by channel index, ++ * and omitted channels keep their defaults. ++ * Examples: ++ * app_interface=1 -> all channels use mctp-netdev ++ * app_interface=1,0,0,0,1 -> ch0/ch4 use mctp-netdev ++ * Invalid values fall back to the default map. ++ */ ++static const uint app_interface_defaults[MMBI_MAX_CHANNELS] = { ++ [0] = MMBI_APP_INTF_MCTP_NETDEV, ++}; + -+ wake_up_interruptible(&oob->wq); ++static uint app_interface[MMBI_MAX_CHANNELS] = { [0] = MMBI_APP_INTF_MCTP_NETDEV }; ++static int app_interface_count; ++module_param_array(app_interface, uint, &app_interface_count, 0444); ++MODULE_PARM_DESC(app_interface, ++ "App interface per channel: 0=ioctl, 1=mctp-netdev; one value applies to all channels"); ++ ++static const char * ++aspeed_host_pcie_mmbi_app_interface_name(enum mmbi_app_interface intf) ++{ ++ switch (intf) { ++ case MMBI_APP_INTF_MCTP_NETDEV: ++ return "mctp-netdev"; ++ case MMBI_APP_INTF_IOCTL: ++ default: ++ return "ioctl"; + } +} + -+static void ast2700_espi_oob_reset(struct ast2700_espi *espi) ++static int aspeed_host_pcie_mmbi_validate_app_interface(struct device *dev) +{ -+ struct ast2700_espi_oob *oob; -+ dma_addr_t tx_addr, rx_addr; -+ uint32_t reg; + int i; + -+ oob = &espi->oob; -+ -+ writel(0x0, espi->regs + ESPI_CH2_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_CH2_INT_STS); -+ -+ reg = readl(espi->regs + ESPI_CH2_CTRL); -+ reg &= ~(ESPI_CH2_CTRL_TX_RST -+ | ESPI_CH2_CTRL_RX_RST -+ | ESPI_CH2_CTRL_TX_DMA_EN -+ | ESPI_CH2_CTRL_RX_DMA_EN -+ | ESPI_CH2_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ for (i = 0; i < app_interface_count; i++) { ++ if (app_interface[i] > MMBI_APP_INTF_MCTP_NETDEV) { ++ dev_warn(dev, ++ "invalid app_interface[%d]=%u, using defaults\n", ++ i, app_interface[i]); ++ return -EINVAL; ++ } ++ } + -+ udelay(1); ++ return 0; ++} + -+ reg |= (ESPI_CH2_CTRL_TX_RST | ESPI_CH2_CTRL_RX_RST); -+ writel(reg, espi->regs + ESPI_CH2_CTRL); ++static enum mmbi_app_interface ++aspeed_host_pcie_mmbi_get_app_interface(int channel, bool use_defaults) ++{ ++ if (use_defaults) ++ return app_interface_defaults[channel]; + -+ if (oob->dma.enable) { -+ tx_addr = oob->dma.tx_addr; -+ rx_addr = oob->dma.rx_addr; ++ if (app_interface_count == 1) ++ return app_interface[0]; + -+ for (i = 0; i < OOB_DMA_DESC_NUM; ++i) { -+ oob->dma.txd_virt[i].data_addrh = tx_addr >> 32; -+ oob->dma.txd_virt[i].data_addrl = tx_addr & 0xffffffff; -+ tx_addr += PAGE_SIZE; ++ if (channel < app_interface_count) ++ return app_interface[channel]; + -+ oob->dma.rxd_virt[i].data_addrh = rx_addr >> 32; -+ oob->dma.rxd_virt[i].data_addrl = rx_addr & 0xffffffff; -+ oob->dma.rxd_virt[i].dirty = 0; -+ rx_addr += PAGE_SIZE; -+ } ++ return app_interface_defaults[channel]; ++} + -+ writel(oob->dma.txd_addr >> 32, espi->regs + ESPI_CH2_TX_DMAH); -+ writel(oob->dma.txd_addr & 0xffffffff, espi->regs + ESPI_CH2_TX_DMAL); -+ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_CH2_TX_DESC_RPTR); -+ writel(0x0, espi->regs + ESPI_CH2_TX_DESC_WPTR); -+ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_CH2_TX_DESC_EPTR); ++static void ++aspeed_host_pcie_mmbi_init_app_interfaces(struct mmbi_ins_desc *mmbi_desc, ++ bool use_defaults) ++{ ++ int i; + -+ writel(oob->dma.rxd_addr >> 32, espi->regs + ESPI_CH2_RX_DMAH); -+ writel(oob->dma.rxd_addr & 0xffffffff, espi->regs + ESPI_CH2_RX_DMAL); -+ writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_CH2_RX_DESC_RPTR); -+ writel(0x0, espi->regs + ESPI_CH2_RX_DESC_WPTR); -+ writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_CH2_RX_DESC_EPTR); ++ for (i = 0; i < MMBI_MAX_CHANNELS; i++) ++ mmbi_desc->chan_desc[i].app_interface = ++ aspeed_host_pcie_mmbi_get_app_interface(i, ++ use_defaults); ++} + -+ reg = readl(espi->regs + ESPI_CH2_CTRL) -+ | ESPI_CH2_CTRL_TX_DMA_EN -+ | ESPI_CH2_CTRL_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CH2_CTRL); ++static void aspeed_host_pcie_mmbi_log_app_interfaces(struct device *dev, ++ struct mmbi_ins_desc *mmbi_desc, ++ int bar) ++{ ++ struct mmbi_chan_desc *chan_desc; ++ const char *interface; ++ int i; + -+ /* activate RX DMA to make OOB_FREE */ -+ reg = readl(espi->regs + ESPI_CH2_RX_DESC_WPTR) | ESPI_CH2_RX_DESC_WPTR_VALID; -+ writel(reg, espi->regs + ESPI_CH2_RX_DESC_WPTR); ++ for (i = 0; i < mmbi_desc->num_of_channels; i++) { ++ chan_desc = &mmbi_desc->chan_desc[i]; ++ interface = aspeed_host_pcie_mmbi_app_interface_name(chan_desc->app_interface); ++ dev_info(dev, "BAR %d channel %d application interface: %s\n", ++ bar, i, interface); + } -+ -+ writel(ESPI_CH2_INT_EN_RX_CMPLT, espi->regs + ESPI_CH2_INT_EN); -+ -+ reg = readl(espi->regs + ESPI_CH2_CTRL) | ESPI_CH2_CTRL_SW_RDY; -+ writel(reg, espi->regs + ESPI_CH2_CTRL); +} + -+static int ast2700_espi_oob_probe(struct ast2700_espi *espi) ++static int aspeed_pci_host_mmbi_setup(struct pci_dev *pdev) +{ -+ struct ast2700_espi_oob *oob; -+ struct device *dev; -+ int rc; ++ struct aspeed_host_pcie_mmbi *mmbi = pci_get_drvdata(pdev); ++ struct aspeed_host_pcie_mmbi_ins *ins; ++ struct device *dev = &pdev->dev; ++ struct mmbi_ins_desc *mmbi_desc; ++ int i, ret, instance_id; ++ int last_ret = -ENODEV; ++ bool use_default_app_interfaces; ++ resource_size_t start, size; ++ ++ ret = aspeed_host_pcie_mmbi_validate_app_interface(dev); ++ use_default_app_interfaces = ret != 0; ++ ++ instance_id = 0; ++ for (i = 0; i < PCI_STD_NUM_BARS; i++) { ++ ins = &mmbi->instances[i]; ++ mmbi_desc = &ins->mmbi_desc; ++ start = pci_resource_start(pdev, i); ++ size = pci_resource_len(pdev, i); ++ ++ if (!start || !size) { ++ dev_err(dev, ++ "Invalid BAR %d with start 0x%llx and size 0x%llx\n", ++ i, (unsigned long long)start, ++ (unsigned long long)size); ++ continue; ++ } + -+ dev = espi->dev; ++ mmbi_desc->desc_virt = pci_ioremap_bar(pdev, i); ++ if (!mmbi_desc->desc_virt) { ++ dev_err(dev, "Failed to ioremap BAR %d\n", i); ++ continue; ++ } ++ mmbi_desc->dev = dev; ++ mmbi_desc->role = MMBI_ROLE_HOST; + -+ oob = &espi->oob; ++ aspeed_host_pcie_mmbi_init_app_interfaces(mmbi_desc, ++ use_default_app_interfaces); ++ ret = mmbi_instance_init(mmbi_desc); ++ if (ret) { ++ dev_info(dev, "Failed to initialize MMBI at bar %d, error %d\n", i, ret); ++ /* Unmap the previously mapped BAR */ ++ iounmap(mmbi_desc->desc_virt); ++ last_ret = ret; ++ } else { ++ ins->instance_index = instance_id++; ++ ins->bar_index = i; ++ ins->valid = true; ++ ins->dev_name = devm_kasprintf(dev, GFP_KERNEL, "mmbi_host_ins%d", ins->instance_index); ++ aspeed_host_pcie_mmbi_log_app_interfaces(dev, mmbi_desc, i); ++ ++ if (mmbi_desc->host_int_type == MMBI_HOST_INT_PCIE) { ++ if (mmbi_desc->host_int_location > mmbi->msi_nums) { ++ dev_err(dev, ++ "Invalid host interrupt location %d for MMBI instance at BAR %d, use MSI 0\n", ++ mmbi_desc->host_int_location, ++ i); ++ ins->msi_index = 0; ++ } else { ++ ins->msi_index = mmbi_desc->host_int_location; ++ } ++ } ++ } ++ } + -+ init_waitqueue_head(&oob->wq); ++ if (!instance_id) ++ return last_ret; + -+ spin_lock_init(&oob->lock); ++ return 0; ++} + -+ mutex_init(&oob->tx_mtx); -+ mutex_init(&oob->rx_mtx); ++static int aspeed_pci_host_pcie_mmbi_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ struct aspeed_host_pcie_mmbi *mmbi; ++ int rc = 0; + -+ oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); -+ if (oob->dma.enable) { -+ oob->dma.txd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, &oob->dma.txd_addr, GFP_KERNEL); -+ if (!oob->dma.txd_virt) { -+ dev_err(dev, "cannot allocate DMA TX descriptor\n"); -+ return -ENOMEM; -+ } -+ oob->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.tx_addr, GFP_KERNEL); -+ if (!oob->dma.tx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); -+ return -ENOMEM; -+ } ++ mmbi = devm_kzalloc(&pdev->dev, sizeof(*mmbi), GFP_KERNEL); ++ if (!mmbi) ++ return -ENOMEM; + -+ oob->dma.rxd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, &oob->dma.rxd_addr, GFP_KERNEL); -+ if (!oob->dma.rxd_virt) { -+ dev_err(dev, "cannot allocate DMA RX descriptor\n"); -+ return -ENOMEM; -+ } ++ mmbi->dev = &pdev->dev; + -+ oob->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, &oob->dma.rx_addr, GFP_KERNEL); -+ if (!oob->dma.rx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); -+ return -ENOMEM; -+ } -+ } ++ rc = pci_enable_device(pdev); ++ if (rc) ++ return rc; + -+ oob->mdev.parent = dev; -+ oob->mdev.minor = MISC_DYNAMIC_MINOR; -+ oob->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-oob%d", DEVICE_NAME, espi->dev_id); -+ oob->mdev.fops = &ast2700_espi_oob_fops; -+ rc = misc_register(&oob->mdev); ++ pci_set_master(pdev); ++ pci_set_drvdata(pdev, mmbi); ++ rc = aspeed_pci_host_mmbi_setup(pdev); + if (rc) { -+ dev_err(dev, "cannot register device %s\n", oob->mdev.name); -+ return rc; ++ dev_err(&pdev->dev, "Failed to setup MMBI instances\n"); ++ goto err_pci; + } + -+ ast2700_espi_oob_reset(espi); -+ ++ dev_info(&pdev->dev, "ASPEED Host PCIe MMBI device probed successfully\n"); + return 0; ++ ++err_pci: ++ pci_disable_device(pdev); ++ return dev_err_probe(&pdev->dev, rc, ++ "Failed to probe ASPEED Host PCIe MMBI device\n"); +} + -+static int ast2700_espi_oob_remove(struct ast2700_espi *espi) ++static void aspeed_pci_host_pcie_mmbi_remove(struct pci_dev *pdev) +{ -+ struct ast2700_espi_oob *oob; -+ struct device *dev; -+ uint32_t reg; -+ -+ dev = espi->dev; -+ -+ oob = &espi->oob; ++ struct aspeed_host_pcie_mmbi *mmbi; ++ struct aspeed_host_pcie_mmbi_ins *ins; ++ int i; + -+ writel(0x0, espi->regs + ESPI_CH2_INT_EN); ++ mmbi = pci_get_drvdata(pdev); ++ for (i = 0; i < PCI_STD_NUM_BARS; i++) { ++ ins = &mmbi->instances[i]; ++ if (ins->valid) { ++ mmbi_instance_remove(&ins->mmbi_desc); ++ pci_iounmap(pdev, ins->mmbi_desc.desc_virt); ++ } ++ } + -+ reg = readl(espi->regs + ESPI_CH2_CTRL); -+ reg &= ~(ESPI_CH2_CTRL_TX_DMA_EN -+ | ESPI_CH2_CTRL_RX_DMA_EN -+ | ESPI_CH2_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ pci_disable_device(pdev); ++} + -+ if (oob->dma.enable) { -+ dmam_free_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, -+ oob->dma.txd_virt, oob->dma.txd_addr); -+ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, -+ oob->dma.tx_virt, oob->dma.tx_addr); -+ dmam_free_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, -+ oob->dma.rxd_virt, oob->dma.rxd_addr); -+ dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, -+ oob->dma.rx_virt, oob->dma.rx_addr); -+ } ++static struct pci_device_id aspeed_host_pcie_mmbi_pci_ids[] = { ++ { PCI_DEVICE(0x1A03, 0x2402), .class = 0x0C0C00, .class_mask = (0xFFFF00)}, ++ { 0, } ++}; + -+ mutex_destroy(&oob->tx_mtx); -+ mutex_destroy(&oob->rx_mtx); ++MODULE_DEVICE_TABLE(pci, aspeed_host_pcie_mmbi_pci_ids); + -+ misc_deregister(&oob->mdev); ++static struct pci_driver aspeed_host_pcie_mmbi_driver = { ++ .name = DRIVER_NAME, ++ .id_table = aspeed_host_pcie_mmbi_pci_ids, ++ .probe = aspeed_pci_host_pcie_mmbi_probe, ++ .remove = aspeed_pci_host_pcie_mmbi_remove, ++}; + -+ return 0; ++static int __init aspeed_host_pcie_mmbi_init(void) ++{ ++ return pci_register_driver(&aspeed_host_pcie_mmbi_driver); +} + -+/* flash channel (CH3) */ -+static long ast2700_espi_flash_get_rx(struct file *fp, -+ struct ast2700_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) ++static void aspeed_host_pcie_mmbi_exit(void) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ unsigned long flags; -+ uint32_t pkt_len; -+ uint8_t *pkt; -+ int i, rc; -+ -+ rc = 0; ++ /* unregister pci driver */ ++ pci_unregister_driver(&aspeed_host_pcie_mmbi_driver); ++} + -+ espi = container_of(flash, struct ast2700_espi, flash); ++late_initcall(aspeed_host_pcie_mmbi_init); ++module_exit(aspeed_host_pcie_mmbi_exit); + -+ if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&flash->rx_mtx)) -+ return -EAGAIN; ++MODULE_AUTHOR("YH Chung "); ++MODULE_DESCRIPTION("ASPEED Host PCIE MMBI Transport Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.c b/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.c +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.c 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,216 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Implements MMBI protocol for BMC side with VPSCB buffer type ++ * Copyright 2026 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aspeed-mmbi.h" ++#include "aspeed-mmbi-internal.h" ++#include "aspeed-mmbi-bmc.h" ++ ++#define MMBI_PUT_U32_MSB(base, off, val) \ ++ do { \ ++ for (int __i = 0; __i < 4; __i++) { \ ++ iowrite8((u8)((val) >> (24 - (__i * 8))), \ ++ (base) + ((off)++)); \ ++ } \ ++ } while (0) + -+ if (!flash->rx_ready) { -+ rc = -ENODATA; -+ goto unlock_mtx_n_out; -+ } -+ } else { -+ mutex_lock(&flash->rx_mtx); ++static void mmbi_channel_state_handler(struct mmbi_chan_desc *chan, u8 __iomem *desc_virt) ++{ ++ enum mmbi_state prev_state, cur_state; ++ struct mmbi_buf_vpscb *vpscb; ++ u8 __iomem *host_ros_virt, *host_rws_virt; ++ u32 unhandled_len, avail_len; + -+ if (!flash->rx_ready) { -+ rc = wait_event_interruptible(flash->wq, flash->rx_ready); -+ if (rc == -ERESTARTSYS) { -+ rc = -EINTR; -+ goto unlock_mtx_n_out; -+ } -+ } -+ } ++ prev_state = chan->priv->state; + -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ reg = readl(espi->regs + ESPI_CH3_RX_CTRL); -+ cyc = FIELD_GET(ESPI_CH3_RX_CTRL_CYC, reg); -+ tag = FIELD_GET(ESPI_CH3_RX_CTRL_TAG, reg); -+ len = FIELD_GET(ESPI_CH3_RX_CTRL_LEN, reg); ++ vpscb = &chan->buffer_desc; ++ host_ros_virt = desc_virt + vpscb->h_ros_p; ++ host_rws_virt = desc_virt + vpscb->h_rws_p; ++ mmbi_channel_state_update(chan, desc_virt); ++ cur_state = chan->priv->state; + -+ /* -+ * calculate the length of the rest part of the -+ * eSPI packet to be read from HW and copied to -+ * user space. -+ */ -+ switch (cyc) { -+ case ESPI_FLASH_WRITE: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_flash_rwe); -+ break; -+ case ESPI_FLASH_READ: -+ case ESPI_FLASH_ERASE: -+ pkt_len = sizeof(struct espi_flash_rwe); ++ switch (cur_state) { ++ case INIT_MISMATCH: ++ memset_io(host_ros_virt, 0, 8); ++ memset_io(host_rws_virt, 0, 8); ++ mmbi_set_up(host_ros_virt); ++ chan->priv->state = INIT_COMPLETED; + break; -+ case ESPI_FLASH_SUC_CMPLT_D_MIDDLE: -+ case ESPI_FLASH_SUC_CMPLT_D_FIRST: -+ case ESPI_FLASH_SUC_CMPLT_D_LAST: -+ case ESPI_FLASH_SUC_CMPLT_D_ONLY: -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + -+ sizeof(struct espi_flash_cmplt); ++ case NORMAL_RUNTIME: ++ mmbi_set_ready(host_ros_virt); ++ ++ unhandled_len = mmbi_channel_unhandled_length(host_ros_virt, host_rws_virt, chan->h2b_l); ++ if (unhandled_len >= MMBI_PKT_MIN_SIZE) ++ chan->priv->rx_ready = true; ++ else ++ chan->priv->rx_ready = false; ++ avail_len = mmbi_channel_avail_length(host_rws_virt, host_ros_virt, chan->b2h_l); ++ if (avail_len <= MMBI_PKT_MIN_SIZE) ++ chan->priv->tx_ready = false; ++ else ++ chan->priv->tx_ready = true; ++ + break; -+ case ESPI_FLASH_SUC_CMPLT: -+ case ESPI_FLASH_UNSUC_CMPLT: -+ pkt_len = sizeof(struct espi_flash_cmplt); ++ case RESET_REQ_BY_HOST: ++ mmbi_clr_ready(host_ros_virt); ++ mmbi_set_rst(host_ros_virt); ++ chan->priv->state = RESET_ACKED; ++ // TODO: consume all pending data from host and then trigger initialization + break; ++ case RESET_ACKED: ++ mmbi_clr_up(host_ros_virt); ++ chan->priv->state = TRANS_TO_INIT; ++ memset_io(host_ros_virt, 0, 8); ++ memset_io(host_rws_virt, 0, 8); ++ mmbi_set_up(host_ros_virt); ++ chan->priv->state = INIT_COMPLETED; + default: -+ rc = -EFAULT; -+ goto unlock_mtx_n_out; -+ } -+ -+ if (ioc->pkt_len < pkt_len) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; -+ } -+ -+ pkt = vmalloc(pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } -+ -+ hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = cyc; -+ hdr->tag = tag; -+ hdr->len_h = len >> 8; -+ hdr->len_l = len & 0xff; -+ -+ if (flash->dma.enable) { -+ memcpy(hdr + 1, flash->dma.rx_virt, pkt_len - sizeof(*hdr)); -+ } else { -+ for (i = sizeof(*hdr); i < pkt_len; ++i) -+ pkt[i] = readl(espi->regs + ESPI_CH3_RX_DATA) & 0xff; -+ } -+ -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; ++ /* other states do not require action from BMC side */ ++ break; + } + -+ spin_lock_irqsave(&flash->lock, flags); ++ return; ++} + -+ writel(ESPI_CH3_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH3_RX_CTRL); -+ flash->rx_ready = 0; ++static int mmbi_buffer_init_vpscb_bmc(u8 __iomem *buf_virt, struct mmbi_buf_vpscb *buf_desc) ++{ ++ u32 offset; + -+ spin_unlock_irqrestore(&flash->lock, flags); ++ offset = 0; + -+ rc = 0; ++ iowrite8(MMBI_BUFFER_TYPE_VPSCB & MMBI_BUF_TYPE_MASK, buf_virt + offset++); ++ iowrite8(buf_desc->host_int_val_ch & MMBI_INT_VAL_MASK, buf_virt + offset++); ++ iowrite8(buf_desc->bmc_int_val_ch & MMBI_INT_VAL_MASK, buf_virt + offset++); + -+free_n_out: -+ vfree(pkt); ++ memset_io(buf_virt + offset, 0, 5); ++ offset += 5; /* reserved bytes */ + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->rx_mtx); ++ MMBI_PUT_U32_MSB(buf_virt, offset, MMBI_BUF_ADDR_ALIGN(buf_desc->h_ros_p)); ++ MMBI_PUT_U32_MSB(buf_virt, offset, MMBI_BUF_ADDR_ALIGN(buf_desc->h_rws_p)); + -+ return rc; ++ pr_info("%s: h_ros_p=0x%x, h_rws_p=0x%x\n", __func__, ++ buf_desc->h_ros_p, buf_desc->h_rws_p); ++ return 0; +} + -+static long ast2700_espi_flash_put_tx(struct file *fp, -+ struct ast2700_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) ++static int mmbi_channel_init_bmc(u8 __iomem *desc_virt, struct mmbi_chan_desc *chan_desc) +{ -+ uint32_t reg, cyc, tag, len; -+ struct ast2700_espi *espi; -+ struct espi_comm_hdr *hdr; -+ uint8_t *pkt; -+ int i, rc; ++ u32 offset = 0; ++ struct mmbi_buf_vpscb *buffer_desc; + -+ espi = container_of(flash, struct ast2700_espi, flash); ++ chan_desc->priv->peer_ready = false; ++ MMBI_PUT_U32_MSB(desc_virt, offset, MMBI_BUF_ADDR_ALIGN(chan_desc->b2h_ba_offset)); ++ MMBI_PUT_U32_MSB(desc_virt, offset, MMBI_BUF_ADDR_ALIGN(chan_desc->h2b_ba_offset)); ++ MMBI_PUT_U32_MSB(desc_virt, offset, chan_desc->b2h_l); ++ MMBI_PUT_U32_MSB(desc_virt, offset, chan_desc->h2b_l); + -+ if (!mutex_trylock(&flash->tx_mtx)) -+ return -EAGAIN; ++ pr_info("%s: b2h_ba_offset=0x%x, h2b_ba_offset=0x%x\n", __func__, ++ chan_desc->b2h_ba_offset, chan_desc->h2b_ba_offset); ++ pr_info("%s: b2h_l=0x%x, h2b_l=0x%x\n", __func__, chan_desc->b2h_l, ++ chan_desc->h2b_l); ++ pr_info("%s: buffer_type=%u\n", __func__, chan_desc->buffer_type); + -+ reg = readl(espi->regs + ESPI_CH3_TX_CTRL); -+ if (reg & ESPI_CH3_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_mtx_n_out; ++ if (chan_desc->buffer_type == MMBI_BUFFER_TYPE_VPSCB) { ++ buffer_desc = &chan_desc->buffer_desc; ++ return mmbi_buffer_init_vpscb_bmc(desc_virt + offset, buffer_desc); + } + -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } ++ pr_err("\t%s: unsupported buffer type %d\n", __func__, ++ chan_desc->buffer_type); ++ return -EINVAL; ++} + -+ hdr = (struct espi_comm_hdr *)pkt; ++void mmbi_channel_irq_bmc(struct mmbi_chan_desc *chan) ++{ ++ mmbi_channel_state_handler(chan, chan->mmbi->desc_virt); ++} ++EXPORT_SYMBOL_GPL(mmbi_channel_irq_bmc); + -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++int mmbi_instance_init_bmc(struct mmbi_ins_desc *mmbi) ++{ ++ int rc, offset; ++ u32 i; ++ u8 __iomem *desc_virt; ++ struct mmbi_buf_vpscb *vpscb; + -+ /* -+ * common header (i.e. cycle type, tag, and length) -+ * part is written to HW registers -+ */ -+ if (flash->dma.enable) { -+ memcpy(flash->dma.tx_virt, hdr + 1, ioc->pkt_len - sizeof(*hdr)); -+ dma_wmb(); -+ } else { -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_CH3_TX_DATA); ++ if (mmbi->num_of_channels > MMBI_MAX_CHANNELS) { ++ dev_err(mmbi->dev, "%s: invalid number of instances %d\n", ++ __func__, mmbi->num_of_channels); ++ return -EINVAL; + } + -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ desc_virt = mmbi->desc_virt; ++ i = FIELD_PREP((u32)MMBI_NOI_MASK, mmbi->num_of_channels); ++ i |= FIELD_PREP((u32)MMBI_OS_USE_MASK, mmbi->os_use); ++ dev_info(mmbi->dev, "%s: MMBI version 0x%x, os_use %u, num_of_channels %u i %u\n", ++ __func__, mmbi->mmbi_version, mmbi->os_use, mmbi->num_of_channels, i); + -+ reg = FIELD_PREP(ESPI_CH3_TX_CTRL_CYC, cyc) -+ | FIELD_PREP(ESPI_CH3_TX_CTRL_TAG, tag) -+ | FIELD_PREP(ESPI_CH3_TX_CTRL_LEN, len) -+ | ESPI_CH3_TX_CTRL_TRIG_PEND; -+ writel(reg, espi->regs + ESPI_CH3_TX_CTRL); ++ memcpy_toio(desc_virt, MMBI_SIGNATURE, sizeof(MMBI_SIGNATURE) - 1); ++ desc_virt += sizeof(MMBI_SIGNATURE) - 1; + -+ rc = 0; ++ iowrite8(mmbi->mmbi_version & MMBI_VERSION_MASK, desc_virt++); ++ iowrite8(i, desc_virt++); + -+free_n_out: -+ vfree(pkt); ++ mmbi->chan_desc[0].priv->state = INIT_IN_PROGRESS; ++ mmbi->chan_desc[0].index = 0; ++ mmbi->chan_desc[0].mmbi = mmbi; ++ rc = mmbi_channel_init_bmc(desc_virt, &mmbi->chan_desc[0]); ++ if (rc) { ++ dev_err(mmbi->dev, "%s: failed to init channel 0\n", __func__); ++ return rc; ++ } ++ desc_virt += MMBI_DESC_SIZE_CHANNEL; + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->tx_mtx); ++ iowrite8(mmbi->host_int_type & MMBI_INT_TYPE_MASK, desc_virt++); ++ iowrite8(mmbi->host_int_location, desc_virt++); + -+ return rc; -+} ++ memset_io(desc_virt, 0, 3); ++ desc_virt += 3; /* reserved bytes */ ++ iowrite8(mmbi->host_int_value, desc_virt++); ++ iowrite8(mmbi->bmc_int_type & MMBI_INT_TYPE_MASK, desc_virt++); ++ offset = desc_virt - mmbi->desc_virt; ++ desc_virt += sizeof(mmbi->bmc_int_location); ++ MMBI_PUT_U32_MSB(mmbi->desc_virt, offset, mmbi->bmc_int_location); + -+static long ast2700_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -+{ -+ struct ast2700_espi_flash *flash; -+ struct aspeed_espi_ioc ioc; ++ memset_io(desc_virt, 0, 4); ++ desc_virt += 4; /* reserved bytes */ + -+ flash = container_of(fp->private_data, struct ast2700_espi_flash, mdev); ++ iowrite8(mmbi->bmc_int_value, desc_virt++); + -+ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) -+ return -EFAULT; ++ memset_io(desc_virt, 0, 8); ++ desc_virt += 8; /* reserved bytes */ + -+ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) -+ return -EINVAL; ++ if (mmbi->num_of_channels > 1) { ++ for (i = 1; i < mmbi->num_of_channels; i++) { ++ mmbi->chan_desc[i].priv->state = INIT_IN_PROGRESS; ++ mmbi->chan_desc[i].index = i; ++ mmbi->chan_desc[i].mmbi = mmbi; ++ rc = mmbi_channel_init_bmc(desc_virt, &mmbi->chan_desc[i]); ++ if (rc) { ++ dev_err(mmbi->dev, "%s: failed to init channel %d\n", __func__, i); ++ return rc; ++ } ++ desc_virt += MMBI_DESC_SIZE_CHANNEL; ++ } ++ } + -+ switch (cmd) { -+ case ASPEED_ESPI_FLASH_GET_RX: -+ return ast2700_espi_flash_get_rx(fp, flash, &ioc); -+ case ASPEED_ESPI_FLASH_PUT_TX: -+ return ast2700_espi_flash_put_tx(fp, flash, &ioc); -+ }; ++ for (i = 0; i < mmbi->num_of_channels; i++) { ++ vpscb = &mmbi->chan_desc[i].buffer_desc; ++ memset_io(mmbi->desc_virt + vpscb->h_ros_p, 0, 8); ++ memset_io(mmbi->desc_virt + vpscb->h_rws_p, 0, 8); + -+ return -EINVAL; ++ mmbi_set_up(mmbi->desc_virt + vpscb->h_ros_p); ++ mmbi_set_ready(mmbi->desc_virt + vpscb->h_ros_p); ++ mmbi->chan_desc[i].priv->state = INIT_COMPLETED; ++ } ++ ++ return rc; +} ++EXPORT_SYMBOL_GPL(mmbi_instance_init_bmc); +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.h b/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.h +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi-bmc.h 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright 2026 Aspeed Technology Inc. ++ */ ++#ifndef __ASPEED_MMBI_BMC_H__ ++#define __ASPEED_MMBI_BMC_H__ + -+static const struct file_operations ast2700_espi_flash_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2700_espi_flash_ioctl, -+}; ++#include "aspeed-mmbi.h" + -+static void ast2700_espi_flash_isr(struct ast2700_espi *espi) -+{ -+ struct ast2700_espi_flash *flash; -+ unsigned long flags; -+ uint32_t sts; ++int mmbi_instance_init_bmc(struct mmbi_ins_desc *mmbi); ++void mmbi_channel_irq_bmc(struct mmbi_chan_desc *chan); + -+ flash = &espi->flash; ++#endif /* __ASPEED_MMBI_BMC_H__ */ +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.c b/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.c +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.c 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,230 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Implements MMBI protocol for Host side with VPSCB buffer type ++ * Copyright 2026 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aspeed-mmbi.h" ++#include "aspeed-mmbi-internal.h" ++#include "aspeed-mmbi-host.h" + -+ sts = readl(espi->regs + ESPI_CH3_INT_STS); ++static void mmbi_channel_state_handler(struct mmbi_chan_desc *chan, u8 __iomem *desc_virt) ++{ ++ enum mmbi_state prev_state, cur_state; ++ struct mmbi_buf_vpscb *vpscb; ++ u8 __iomem *host_rws_virt; ++ u8 __iomem *host_ros_virt; ++ u32 host_int_location; ++ u32 unhandled_len, avail_len; + -+ if (sts & ESPI_CH3_INT_STS_RX_CMPLT) { -+ writel(ESPI_CH3_INT_STS_RX_CMPLT, espi->regs + ESPI_CH3_INT_STS); ++ prev_state = chan->priv->state; + -+ spin_lock_irqsave(&flash->lock, flags); -+ flash->rx_ready = true; -+ spin_unlock_irqrestore(&flash->lock, flags); ++ host_int_location = chan->mmbi->host_int_location; ++ vpscb = &chan->buffer_desc; ++ host_rws_virt = desc_virt + vpscb->h_rws_p; ++ host_ros_virt = desc_virt + vpscb->h_ros_p; ++ mmbi_channel_state_update(chan, desc_virt); ++ cur_state = chan->priv->state; + -+ wake_up_interruptible(&flash->wq); ++ switch (cur_state) { ++ case INIT_COMPLETED: ++ mmbi_set_ready(host_rws_virt); ++ mmbi_set_up(host_rws_virt); ++ chan->priv->state = NORMAL_RUNTIME; ++ break; ++ case NORMAL_RUNTIME: ++ mmbi_set_ready(host_rws_virt); ++ ++ unhandled_len = mmbi_channel_unhandled_length(host_rws_virt, ++ host_ros_virt, chan->b2h_l); ++ if (unhandled_len >= MMBI_PKT_MIN_SIZE) ++ chan->priv->rx_ready = true; ++ else ++ chan->priv->rx_ready = false; ++ avail_len = mmbi_channel_avail_length(host_ros_virt, host_rws_virt, chan->h2b_l); ++ if (avail_len <= MMBI_PKT_MIN_SIZE) ++ chan->priv->tx_ready = false; ++ else ++ chan->priv->tx_ready = true; ++ break; ++ case RESET_REQ_BY_BMC: ++ // TODO: consume all data from B2H buffer ++ mmbi_clr_ready(host_rws_virt); ++ mmbi_set_rst(host_rws_virt); ++ chan->priv->state = RESET_ACKED; ++ break; ++ default: ++ /* other states do not require action from host side */ ++ break; + } +} + -+static void ast2700_espi_flash_reset(struct ast2700_espi *espi) ++static int mmbi_instance_signature_check(u8 __iomem *desc_virt) +{ -+ uint32_t reg; -+ uint64_t mask; -+ struct ast2700_espi_flash *flash = &espi->flash; -+ -+ writel(0x0, espi->regs + ESPI_CH3_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_CH3_INT_STS); -+ -+ reg = readl(espi->regs + ESPI_CH3_CTRL); -+ reg &= ~(ESPI_CH3_CTRL_TX_RST -+ | ESPI_CH3_CTRL_RX_RST -+ | ESPI_CH3_CTRL_TX_DMA_EN -+ | ESPI_CH3_CTRL_RX_DMA_EN -+ | ESPI_CH3_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH3_CTRL); -+ -+ udelay(1); ++ char signature[sizeof(MMBI_SIGNATURE) - 1]; + -+ reg |= (ESPI_CH3_CTRL_TX_RST | ESPI_CH3_CTRL_RX_RST); -+ writel(reg, espi->regs + ESPI_CH3_CTRL); ++ memcpy_fromio(signature, desc_virt, sizeof(MMBI_SIGNATURE) - 1); ++ if (memcmp(signature, MMBI_SIGNATURE, sizeof(MMBI_SIGNATURE) - 1) != 0) ++ return -EINVAL; + -+ if (flash->edaf.mode == EDAF_MODE_MIX) { -+ mask = ~(flash->edaf.size - 1); -+ writel(mask >> 32, espi->regs + ESPI_CH3_EDAF_MASKH); -+ writel(mask & 0xffffffff, espi->regs + ESPI_CH3_EDAF_MASKL); -+ writel(flash->edaf.taddr >> 32, espi->regs + ESPI_CH3_EDAF_TADDRH); -+ writel(flash->edaf.taddr & 0xffffffff, espi->regs + ESPI_CH3_EDAF_TADDRL); -+ } ++ return 0; ++} + -+ reg = readl(espi->regs + ESPI_CH3_CTRL) & ~ESPI_CH3_CTRL_EDAF_MODE; -+ reg |= FIELD_PREP(ESPI_CH3_CTRL_EDAF_MODE, flash->edaf.mode); -+ writel(reg, espi->regs + ESPI_CH3_CTRL); ++static int mmbi_chan_init_vpscb_host(u8 __iomem *buf_virt, struct mmbi_buf_vpscb *buf_desc) ++{ ++ u32 offset = 0; + -+ if (flash->dma.enable) { -+ writel(flash->dma.tx_addr >> 32, espi->regs + ESPI_CH3_TX_DMAH); -+ writel(flash->dma.tx_addr & 0xffffffff, espi->regs + ESPI_CH3_TX_DMAL); -+ writel(flash->dma.rx_addr >> 32, espi->regs + ESPI_CH3_RX_DMAH); -+ writel(flash->dma.rx_addr & 0xffffffff, espi->regs + ESPI_CH3_RX_DMAL); ++ buf_desc->host_int_val_ch = ioread8(buf_virt + offset++) & MMBI_INT_VAL_MASK; ++ buf_desc->bmc_int_val_ch = ioread8(buf_virt + offset++) & MMBI_INT_VAL_MASK; + -+ reg = readl(espi->regs + ESPI_CH3_CTRL) -+ | ESPI_CH3_CTRL_TX_DMA_EN -+ | ESPI_CH3_CTRL_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CH3_CTRL); -+ } ++ offset += 5; /* reserved bytes */ + -+ writel(ESPI_CH3_INT_EN_RX_CMPLT, espi->regs + ESPI_CH3_INT_EN); ++ memcpy_fromio(&buf_desc->h_ros_p, buf_virt + offset, sizeof(buf_desc->h_ros_p)); ++ memcpy_fromio(&buf_desc->h_rws_p, buf_virt + offset + 4, sizeof(buf_desc->h_rws_p)); ++ buf_desc->h_ros_p = be32_to_cpu(buf_desc->h_ros_p); ++ buf_desc->h_rws_p = be32_to_cpu(buf_desc->h_rws_p); ++ buf_desc->h_ros_p = MMBI_BUF_ADDR_ALIGN(buf_desc->h_ros_p); ++ buf_desc->h_rws_p = MMBI_BUF_ADDR_ALIGN(buf_desc->h_rws_p); + -+ reg = readl(espi->regs + ESPI_CH3_CTRL) | ESPI_CH3_CTRL_SW_RDY; -+ writel(reg, espi->regs + ESPI_CH3_CTRL); ++ pr_info("%s: h_ros_p=0x%x, h_rws_p=0x%x\n", __func__, ++ buf_desc->h_ros_p, buf_desc->h_rws_p); ++ return 0; +} + -+static int ast2700_espi_flash_probe(struct ast2700_espi *espi) ++static int mmbi_channel_init_host(u8 __iomem *desc_virt, struct mmbi_chan_desc *chan_desc) +{ -+ struct ast2700_espi_flash *flash; -+ struct device_node *np; -+ struct resource res; -+ struct device *dev; -+ void *virt; ++ struct mmbi_buf_vpscb *buffer_desc; + int rc; + -+ dev = espi->dev; -+ -+ flash = &espi->flash; ++ if (!desc_virt || !IS_ALIGNED((unsigned long)desc_virt, sizeof(long))) { ++ pr_err("%s: invalid desc_virt address %p\n", __func__, desc_virt); ++ return -EINVAL; ++ } + -+ init_waitqueue_head(&flash->wq); ++ chan_desc->priv->peer_ready = false; ++ memcpy_fromio(&chan_desc->b2h_ba_offset, desc_virt, sizeof(chan_desc->b2h_ba_offset)); ++ memcpy_fromio(&chan_desc->h2b_ba_offset, desc_virt + 4, sizeof(chan_desc->h2b_ba_offset)); ++ memcpy_fromio(&chan_desc->b2h_l, desc_virt + 8, sizeof(chan_desc->b2h_l)); ++ memcpy_fromio(&chan_desc->h2b_l, desc_virt + 12, sizeof(chan_desc->h2b_l)); ++ chan_desc->b2h_ba_offset = be32_to_cpu(chan_desc->b2h_ba_offset); ++ chan_desc->h2b_ba_offset = be32_to_cpu(chan_desc->h2b_ba_offset); ++ chan_desc->b2h_l = be32_to_cpu(chan_desc->b2h_l); ++ chan_desc->h2b_l = be32_to_cpu(chan_desc->h2b_l); ++ chan_desc->b2h_ba_offset = MMBI_BUF_ADDR_ALIGN(chan_desc->b2h_ba_offset); ++ chan_desc->h2b_ba_offset = MMBI_BUF_ADDR_ALIGN(chan_desc->h2b_ba_offset); ++ desc_virt += 16; ++ chan_desc->buffer_type = ioread8(desc_virt++) & MMBI_BUF_TYPE_MASK; + -+ spin_lock_init(&flash->lock); ++ pr_info("%s: b2h_ba_offset=0x%x, h2b_ba_offset=0x%x\n", __func__, ++ chan_desc->b2h_ba_offset, chan_desc->h2b_ba_offset); ++ pr_info("%s: b2h_l=0x%x, h2b_l=0x%x\n", __func__, chan_desc->b2h_l, chan_desc->h2b_l); ++ pr_info("%s: buffer_type=%u\n", __func__, chan_desc->buffer_type); + -+ mutex_init(&flash->tx_mtx); -+ mutex_init(&flash->rx_mtx); ++ if (chan_desc->buffer_type == MMBI_BUFFER_TYPE_VPSCB) { ++ buffer_desc = &chan_desc->buffer_desc; ++ rc = mmbi_chan_init_vpscb_host(desc_virt, buffer_desc); ++ } + -+ flash->edaf.mode = EDAF_MODE_HW; ++ if (!rc) ++ mmbi_channel_state_handler(chan_desc, chan_desc->mmbi->desc_virt); + -+ of_property_read_u32(dev->of_node, "flash-edaf-mode", &flash->edaf.mode); -+ dev_info(dev, "eDAF mode: 0x%x\n", flash->edaf.mode); -+ if (flash->edaf.mode == EDAF_MODE_MIX) { -+ np = of_parse_phandle(dev->of_node, "flash-edaf-tgt-addr", 0); -+ if (!np || of_address_to_resource(np, 0, &res)) { -+ dev_err(dev, "cannot get eDAF memory region\n"); -+ return -ENODEV; -+ } ++ return rc; ++} + -+ of_node_put(np); ++void mmbi_channel_irq_host(struct mmbi_chan_desc *chan) ++{ ++ mmbi_channel_state_handler(chan, chan->mmbi->desc_virt); ++} ++EXPORT_SYMBOL_GPL(mmbi_channel_irq_host); + -+ flash->edaf.taddr = res.start; -+ flash->edaf.size = resource_size(&res); -+ dev_info(dev, "eDAF address: 0x%llx\n", flash->edaf.taddr); -+ dev_info(dev, "eDAF size: 0x%llx\n", flash->edaf.size); ++int mmbi_instance_init_host(struct mmbi_ins_desc *mmbi) ++{ ++ struct device *dev = mmbi->dev; ++ struct mmbi_chan_desc *chan; ++ int rc; ++ u8 __iomem *desc_virt; ++ u8 chan_idx, val; + -+ virt = devm_ioremap_resource(dev, &res); -+ if (!virt) { -+ dev_err(dev, "cannot map eDAF memory region\n"); -+ return -ENOMEM; -+ } ++ desc_virt = mmbi->desc_virt; ++ if (mmbi_instance_signature_check(desc_virt)) { ++ dev_err(dev, "Invalid MMBI signature\n"); ++ return -EINVAL; + } + -+ flash->dma.enable = of_property_read_bool(dev->of_node, "flash-dma-mode"); -+ if (flash->dma.enable) { -+ flash->dma.tx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.tx_addr, GFP_KERNEL); -+ if (!flash->dma.tx_virt) { -+ dev_err(dev, "cannot allocate DMA TX buffer\n"); -+ return -ENOMEM; -+ } ++ desc_virt += sizeof(MMBI_SIGNATURE) - 1; // exclude signature from descriptor parsing ++ chan_idx = 0; + -+ flash->dma.rx_virt = dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.rx_addr, GFP_KERNEL); -+ if (!flash->dma.rx_virt) { -+ dev_err(dev, "cannot allocate DMA RX buffer\n"); -+ return -ENOMEM; ++ mmbi->mmbi_version = ioread8(desc_virt++) & MMBI_VERSION_MASK; ++ if (mmbi->mmbi_version < MMBI_VERSION_1_0 || mmbi->mmbi_version > MMBI_VERSION_1_1) { ++ dev_err(dev, "Unsupported MMBI version: %d\n", mmbi->mmbi_version); ++ return -EINVAL; ++ } ++ ++ if (mmbi->mmbi_version == MMBI_VERSION_1_1) { ++ val = ioread8(desc_virt++); ++ mmbi->os_use = val & MMBI_OS_USE_MASK; ++ mmbi->num_of_channels = (val & MMBI_NOI_MASK) >> 4; ++ if (mmbi->num_of_channels > MMBI_MAX_CHANNELS || mmbi->num_of_channels == 0) { ++ dev_err(dev, "Invalid number of instances: %d\n", mmbi->num_of_channels); ++ return -EINVAL; + } ++ } else { ++ mmbi->os_use = ioread8(desc_virt++) & MMBI_OS_USE_MASK; + } ++ dev_info(dev, "MMBI version 0x%x, os_use %u, num_of_channels %u\n", ++ mmbi->mmbi_version, mmbi->os_use, mmbi->num_of_channels); + -+ flash->mdev.parent = dev; -+ flash->mdev.minor = MISC_DYNAMIC_MINOR; -+ flash->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-flash%d", DEVICE_NAME, espi->dev_id); -+ flash->mdev.fops = &ast2700_espi_flash_fops; -+ rc = misc_register(&flash->mdev); ++ chan = &mmbi->chan_desc[chan_idx]; ++ chan->index = chan_idx; ++ chan->mmbi = mmbi; ++ rc = mmbi_channel_init_host(desc_virt, chan); + if (rc) { -+ dev_err(dev, "cannot register device %s\n", flash->mdev.name); ++ dev_err(dev, "Failed to initialize MMBI channel %d\n", chan_idx); + return rc; + } + -+ ast2700_espi_flash_reset(espi); -+ ++ desc_virt += MMBI_DESC_SIZE_CHANNEL; ++ chan_idx++; ++ ++ mmbi->host_int_type = ioread8(desc_virt++) & MMBI_INT_TYPE_MASK; ++ mmbi->host_int_location = ioread8(desc_virt++); ++ desc_virt += 3; // reserved 3 bytes ++ mmbi->host_int_value = ioread8(desc_virt++); ++ mmbi->bmc_int_type = ioread8(desc_virt++) & MMBI_INT_TYPE_MASK; ++ memcpy_fromio(&mmbi->bmc_int_location, desc_virt, sizeof(mmbi->bmc_int_location)); ++ mmbi->bmc_int_location = be32_to_cpu(mmbi->bmc_int_location); ++ desc_virt += sizeof(mmbi->bmc_int_location) + 4; // reserved 4 bytes ++ mmbi->bmc_int_value = ioread8(desc_virt++); ++ ++ desc_virt += 8; // reserved 8 bytes ++ ++ dev_info(dev, "host_int_type=%u, host_int_location=0x%x, host_int_value=0x%x\n", ++ mmbi->host_int_type, mmbi->host_int_location, mmbi->host_int_value); ++ dev_info(dev, "bmc_int_type=%u, bmc_int_location=0x%x, bmc_int_value=0x%x\n", ++ mmbi->bmc_int_type, mmbi->bmc_int_location, mmbi->bmc_int_value); ++ dev_info(dev, "offset after init header=0x%lx\n", ++ (unsigned long)(desc_virt - mmbi->desc_virt)); ++ ++ if (chan_idx < mmbi->num_of_channels) { ++ dev_info(dev, "Initializing additional MMBI channels\n"); ++ for (; chan_idx < mmbi->num_of_channels; chan_idx++) { ++ chan = &mmbi->chan_desc[chan_idx]; ++ chan->index = chan_idx; ++ chan->mmbi = mmbi; ++ rc = mmbi_channel_init_host(desc_virt, chan); ++ if (rc) { ++ dev_err(dev, "Failed to initialize MMBI channel %d\n", chan_idx); ++ return rc; ++ } ++ desc_virt += MMBI_DESC_SIZE_CHANNEL; ++ } ++ } + return 0; +} ++EXPORT_SYMBOL_GPL(mmbi_instance_init_host); +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.h b/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.h +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi-host.h 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright 2026 Aspeed Technology Inc. ++ */ ++#ifndef __ASPEED_MMBI_HOST_H__ ++#define __ASPEED_MMBI_HOST_H__ + -+static int ast2700_espi_flash_remove(struct ast2700_espi *espi) -+{ -+ struct ast2700_espi_flash *flash; -+ struct device *dev; -+ uint32_t reg; ++#include "aspeed-mmbi.h" + -+ dev = espi->dev; ++int mmbi_instance_init_host(struct mmbi_ins_desc *mmbi); ++void mmbi_channel_irq_host(struct mmbi_chan_desc *chan); + -+ flash = &espi->flash; ++#endif /* __ASPEED_MMBI_HOST_H__ */ +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi-internal.h b/drivers/soc/aspeed/mmbi/aspeed-mmbi-internal.h +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi-internal.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi-internal.h 2026-09-09 15:51:44.721238026 +0000 +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright 2026 Aspeed Technology Inc. ++ */ ++#ifndef __ASPEED_MMBI_INTERNAL_H__ ++#define __ASPEED_MMBI_INTERNAL_H__ + -+ writel(0x0, espi->regs + ESPI_CH3_INT_EN); ++#include + -+ reg = readl(espi->regs + ESPI_CH3_CTRL); -+ reg &= ~(ESPI_CH3_CTRL_TX_DMA_EN -+ | ESPI_CH3_CTRL_RX_DMA_EN -+ | ESPI_CH3_CTRL_SW_RDY); -+ writel(reg, espi->regs + ESPI_CH3_CTRL); ++#include "aspeed-mmbi.h" ++ ++struct net_device; ++ ++struct mmbi_chan_priv { ++ enum mmbi_state state; /* Current MMBI state of this channel */ ++ struct miscdevice miscdev; /* MMBI char device for this channel */ ++ wait_queue_head_t rx_wait; /* Wait queue for rx data available */ ++ wait_queue_head_t tx_wait; /* Wait queue for tx data available */ ++ bool rx_ready; /* Flag indicating if has data to be read */ ++ bool tx_ready; /* Flag indicating if ready to transmit data */ ++ spinlock_t rx_lock; /* Lock to prevent rx ready flag race */ ++ spinlock_t tx_lock; /* Lock to prevent tx ready flag race */ ++ u32 read_ptr; /* Current cached read pointer */ ++ u32 write_ptr; /* Current cached write pointer */ ++ bool peer_ready; /* Flag indicating peer ready bit */ ++ struct delayed_work poll_work; /* Work struct for polling check status */ ++ bool running; ++ struct mmbi_chan_desc *chan; /* Back pointer used by misc open */ ++ struct net_device *ndev; /* MCTP netdev when the channel selects it */ ++}; ++ ++#endif /* __ASPEED_MMBI_INTERNAL_H__ */ +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi.c b/drivers/soc/aspeed/mmbi/aspeed-mmbi.c +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi.c 2026-09-09 15:51:44.722238011 +0000 +@@ -0,0 +1,939 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * ASPEED MMBI (Memory Mapped Bus Interface) Protocol Driver ++ * ++ * Copyright (c) 2026 ASPEED Technology Inc. ++ */ + -+ if (flash->dma.enable) { -+ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.tx_addr); -+ dmam_free_coherent(dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.rx_addr); -+ } ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ mutex_destroy(&flash->tx_mtx); -+ mutex_destroy(&flash->rx_mtx); ++#include ++#include ++#include + -+ misc_deregister(&flash->mdev); ++#include "aspeed-mmbi.h" ++#include "aspeed-mmbi-internal.h" ++#include "aspeed-mmbi-bmc.h" ++#include "aspeed-mmbi-host.h" + -+ return 0; ++static DEFINE_IDA(mmbi_ida); ++ ++#define MMBI_MCTP_MIN_MTU (sizeof(struct mctp_hdr) + 64) ++#define MMBI_MCTP_RX_BUF_SIZE SZ_4K ++ ++struct mmbi_mctp_netdev { ++ struct mmbi_chan_desc *chan; ++}; ++ ++static void mmbi_channel_start_polling(struct mmbi_chan_desc *chan_desc) ++{ ++ if (chan_desc->priv->running) ++ return; ++ ++ schedule_delayed_work(&chan_desc->priv->poll_work, ++ msecs_to_jiffies(chan_desc->poll_interval_ms)); ++ chan_desc->priv->running = true; +} + -+/* global control */ -+static irqreturn_t ast2700_espi_isr(int irq, void *arg) ++static void mmbi_channel_stop_polling(struct mmbi_chan_desc *chan_desc) +{ -+ uint32_t sts; -+ struct ast2700_espi *espi = (struct ast2700_espi *)arg; ++ if (!chan_desc->priv->running) ++ return; + -+ sts = readl(espi->regs + ESPI_INT_STS); -+ if (!sts) -+ return IRQ_NONE; ++ cancel_delayed_work_sync(&chan_desc->priv->poll_work); ++ chan_desc->priv->running = false; ++} + -+ if (sts & ESPI_INT_STS_CH0) -+ ast2700_espi_perif_isr(espi); ++static void mmbi_update_rd_ptr(u8 __iomem *read_ptr, u32 read_size, u32 read_buf_size) ++{ ++ u32 reg, low, addr, reg_rb; ++ u32 retry_cnt; ++ if (!read_size || (read_size & 3)) { ++ pr_err("%s: read_size must be non-zero and multiple of 4\n", __func__); ++ return; ++ } + -+ if (sts & ESPI_INT_STS_CH1) -+ ast2700_espi_vw_isr(espi); ++ read_ptr += sizeof(u32); /* read pointer is located at offset 4 in the structure */ ++ reg = ioread32(read_ptr); + -+ if (sts & ESPI_INT_STS_CH2) -+ ast2700_espi_oob_isr(espi); ++ low = reg & ~MMBI_PTR_ADDR_MASK; /* bits [1:0] */ ++ addr = reg & MMBI_PTR_ADDR_MASK; /* bits [31:2] */ + -+ if (sts & ESPI_INT_STS_CH3) -+ ast2700_espi_flash_isr(espi); ++ addr = (addr + read_size) % read_buf_size; ++ addr &= MMBI_PTR_ADDR_MASK; ++ retry_cnt = 0; ++ iowrite32(addr | low, read_ptr); ++ do { ++ reg_rb = ioread32(read_ptr); ++ retry_cnt++; ++ if (retry_cnt > 5) { ++ pr_info("%s: read pointer update not reflected after %u retries, reg 0x%x, expected 0x%x\n", ++ __func__, retry_cnt, reg_rb, addr | low); ++ break; ++ } ++ } while (reg_rb != (addr | low)); ++} + -+ if (sts & ESPI_INT_STS_RST_DEASSERT) { -+ ast2700_espi_perif_sw_reset(espi); -+ ast2700_espi_perif_reset(espi); -+ ast2700_espi_vw_reset(espi); -+ ast2700_espi_oob_reset(espi); -+ ast2700_espi_flash_reset(espi); -+ writel(ESPI_INT_STS_RST_DEASSERT, espi->regs + ESPI_INT_STS); ++static void mmbi_update_wr_ptr(u8 __iomem *write_ptr, u32 write_size, u32 write_buf_size) ++{ ++ u32 reg, low, addr, reg_rb; ++ u32 retry_cnt; ++ if (!write_size || (write_size & 3)) { ++ pr_err("%s: write_size must be non-zero and multiple of 4\n", __func__); ++ return; + } + -+ return IRQ_HANDLED; ++ reg = ioread32(write_ptr); ++ ++ low = reg & ~MMBI_PTR_ADDR_MASK; /* bits [1:0] */ ++ addr = reg & MMBI_PTR_ADDR_MASK; /* bits [31:2] */ ++ ++ addr = (addr + write_size) % write_buf_size; ++ addr &= MMBI_PTR_ADDR_MASK; ++ ++ retry_cnt = 0; ++ iowrite32(addr | low, write_ptr); ++ do { ++ reg_rb = ioread32(write_ptr); ++ retry_cnt++; ++ if (retry_cnt > 5) { ++ pr_info("%s: write pointer update not reflected after %u retries, reg 0x%x, expected 0x%x\n", ++ __func__, retry_cnt, reg_rb, addr | low); ++ break; ++ } ++ } while (reg_rb != (addr | low)); +} + -+static int ast2700_espi_probe(struct platform_device *pdev) ++static void mmbi_parse_hdr(u8 __iomem *buf_virt, u32 *payload_len, u8 *padding, ++ u8 *protocol) +{ -+ struct ast2700_espi *espi; -+ struct resource *res; -+ struct device *dev; -+ struct regmap *scu1; -+ uint32_t reg; -+ int rc; ++ u8 hdr[MMBI_PKT_HDR_SIZE]; ++ u32 word24; ++ int i; + -+ dev = &pdev->dev; ++ /* Read header bytes via ioread8() */ ++ for (i = 0; i < MMBI_PKT_HDR_SIZE; i++) ++ hdr[i] = ioread8(buf_virt + i); + -+ espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -+ if (!espi) -+ return -ENOMEM; ++ /* Byte0..2 form the 24-bit field: [23:2]=len, [1:0]=pad */ ++ word24 = ((u32)hdr[0] << 16) | ((u32)hdr[1] << 8) | (u32)hdr[2]; + -+ espi->dev = dev; ++ *padding = word24 & 0x3; ++ *payload_len = (word24 >> 2) * 4 - *padding; ++ *protocol = hdr[3] & MMBI_PKT_PROTOCOL_MASK; ++} + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; -+ } ++static int mmbi_read(struct mmbi_chan_desc *chan, u8 *data, size_t read_len) ++{ ++ struct mmbi_ins_desc *mmbi = chan->mmbi; ++ u32 read_ptr, write_ptr, read_offset, buf_size, unhandled_len, base_addr; ++ u32 data_len, pkt_len; ++ u8 protocol, padding; ++ size_t first_part; ++ u8 __iomem *desc_virt; + -+ scu1 = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); -+ if (IS_ERR(scu1)) { -+ dev_err(dev, "failed to find SCU1 regmap\n"); -+ return PTR_ERR(scu1); -+ } -+ rc = regmap_update_bits(scu1, SCU1_DDR, -+ SCU1_DDR_DIS_ESPI0_AHB | SCU1_DDR_DIS_ESPI1_AHB, -+ 0); ++ if (read_len == 0) ++ return -EINVAL; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(dev, "cannot get resource\n"); -+ return -ENODEV; ++ if (mmbi->role == MMBI_ROLE_BMC) { ++ read_ptr = chan->buffer_desc.h_ros_p; ++ write_ptr = chan->buffer_desc.h_rws_p; ++ buf_size = chan->h2b_l; ++ base_addr = chan->h2b_ba_offset; ++ } else { ++ read_ptr = chan->buffer_desc.h_rws_p; ++ write_ptr = chan->buffer_desc.h_ros_p; ++ buf_size = chan->b2h_l; ++ base_addr = chan->b2h_ba_offset; + } + -+ espi->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(espi->regs)) { -+ dev_err(dev, "cannot map registers\n"); -+ return PTR_ERR(espi->regs); -+ } ++ unhandled_len = mmbi_channel_unhandled_length(mmbi->desc_virt + read_ptr, ++ mmbi->desc_virt + write_ptr, ++ buf_size); + -+ espi->irq = platform_get_irq(pdev, 0); -+ if (espi->irq < 0) { -+ dev_err(dev, "cannot get IRQ number\n"); -+ return -ENODEV; -+ } ++ if (unhandled_len == 0) ++ return 0; + -+ espi->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(espi->clk)) { -+ dev_err(dev, "cannot get clock control\n"); -+ return PTR_ERR(espi->clk); ++ desc_virt = mmbi->desc_virt + base_addr; ++ data_len = 0; ++ read_offset = MMBI_PTR_ADDR_ALIGN(be32_to_cpu(ioread32be(mmbi->desc_virt + read_ptr + sizeof(u32)))); ++ /* MMBI read/write has 4byte unit, so reading header will never have bundary issues */ ++ mmbi_parse_hdr(desc_virt + read_offset, &data_len, &padding, &protocol); ++ ++ if (data_len > read_len) { ++ pr_warn("%s: not enough space(%ld) to read data(%u) for chan %u\n", ++ __func__, read_len, data_len, chan->index); ++ pr_warn("%s: read_offset %d padding %d protocol %d buf_size %d", ++ __func__, read_offset, padding, protocol, buf_size); ++ return -EINVAL; + } ++ pkt_len = MMBI_PKT_HDR_SIZE + data_len + padding; + -+ rc = clk_prepare_enable(espi->clk); -+ if (rc) { -+ dev_err(dev, "cannot enable clocks\n"); -+ return rc; ++ if (unhandled_len > pkt_len) { ++ pr_warn("%s: more data unhandled than current packet length for chan %u, unhandled_len %u pkt_len %u\n", ++ __func__, chan->index, unhandled_len, pkt_len); + } + -+ espi->dev_id = ida_alloc(&ast2700_espi_ida, GFP_KERNEL); -+ if (espi->dev_id < 0) { -+ dev_err(dev, "cannote allocate device ID\n"); -+ return espi->dev_id; ++ /* move offset to payload */ ++ read_offset = (read_offset + MMBI_PKT_HDR_SIZE) % buf_size; ++ if (protocol == MMBI_PROTOCOL_MCTP) { ++ if (read_offset + data_len <= buf_size) { ++ memcpy_fromio(data, desc_virt + read_offset, data_len); ++ } else { ++ first_part = buf_size - read_offset; ++ memcpy_fromio(data, desc_virt + read_offset, first_part); ++ memcpy_fromio(data + first_part, desc_virt, data_len - first_part); ++ } ++ } else { ++ pr_warn("%s: unsupported protocol %u on chan %u, discard packet\n", ++ __func__, protocol, chan->index); + } ++ mmbi_update_rd_ptr(mmbi->desc_virt + read_ptr, pkt_len, buf_size); + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++ return protocol == MMBI_PROTOCOL_MCTP ? data_len : 0; ++} + -+ rc = ast2700_espi_perif_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init CH0, rc=%d\n", rc); -+ return rc; ++static int mmbi_write(struct mmbi_chan_desc *chan, const u8 *data, size_t data_len, u8 protocol) ++{ ++ struct mmbi_ins_desc *mmbi = chan->mmbi; ++ u32 read_ptr, write_ptr, write_offset, buf_size, avail_len, val, base_addr, total_len; ++ u8 __iomem *desc_virt; ++ size_t first_part; ++ u8 padding = 0; ++ ++ if (data_len == 0) ++ return -EINVAL; ++ ++ if (!chan->priv->peer_ready) { ++ pr_info("%s: chan %d peer not ready to receive data", __func__, ++ chan->index); ++ return -EAGAIN; + } + -+ rc = ast2700_espi_vw_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init CH1, rc=%d\n", rc); -+ goto err_remove_perif; ++ if (mmbi->role == MMBI_ROLE_BMC) { ++ read_ptr = chan->buffer_desc.h_rws_p; ++ write_ptr = chan->buffer_desc.h_ros_p; ++ buf_size = chan->b2h_l; ++ base_addr = chan->b2h_ba_offset; ++ } else { ++ read_ptr = chan->buffer_desc.h_ros_p; ++ write_ptr = chan->buffer_desc.h_rws_p; ++ buf_size = chan->h2b_l; ++ base_addr = chan->h2b_ba_offset; + } + -+ rc = ast2700_espi_oob_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init CH2, rc=%d\n", rc); -+ goto err_remove_vw; ++ avail_len = mmbi_channel_avail_length(mmbi->desc_virt + read_ptr, ++ mmbi->desc_virt + write_ptr, ++ buf_size); ++ ++ total_len = data_len + ((protocol == MMBI_PROTOCOL_MCTP) ? 4 : 0); ++ ++ /* at least 8bytes for 4byte header and 4byte data */ ++ if (avail_len < MMBI_PKT_MIN_SIZE) { ++ pr_info("%s: no available buffer to write for chan %u\n", ++ __func__, chan->index); ++ return -EAGAIN; + } + -+ rc = ast2700_espi_flash_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init CH3, rc=%d\n", rc); -+ goto err_remove_oob; ++ if (total_len > avail_len) { ++ pr_info("%s: no available buffer to write for chan %u, requested %d, avail %d\n", ++ __func__, chan->index, total_len, avail_len); ++ return -EAGAIN; + } + -+ rc = devm_request_irq(dev, espi->irq, ast2700_espi_isr, 0, dev_name(dev), espi); -+ if (rc) { -+ dev_err(dev, "cannot request IRQ\n"); -+ goto err_remove_flash; ++ write_offset = MMBI_PTR_ADDR_ALIGN(be32_to_cpu(ioread32be(mmbi->desc_virt + write_ptr))); ++ desc_virt = mmbi->desc_virt + base_addr; ++ /* Multi-protocol header */ ++ if (protocol == MMBI_PROTOCOL_MCTP) { ++ padding = (4 - (data_len & 3)) & 3; /* Pad to 4 bytes */ ++ total_len += padding; ++ val = (data_len + padding) >> 2; ++ val &= 0x3FFFFF; /* 22 bits for length */ ++ iowrite8((val >> 14) & 0xff, desc_virt + write_offset); ++ write_offset++; ++ iowrite8((val >> 6) & 0xff, desc_virt + write_offset); ++ write_offset++; ++ iowrite8(((val << 2) & 0xff) | padding, desc_virt + write_offset); ++ write_offset++; ++ iowrite8(MMBI_PKT_PROTOCOL_MASK & protocol, desc_virt + write_offset); ++ write_offset++; ++ } ++ ++ write_offset %= buf_size; ++ if (write_offset + data_len < buf_size) { ++ memcpy_toio(desc_virt + write_offset, data, data_len); ++ } else { ++ first_part = buf_size - write_offset; ++ memcpy_toio(desc_virt + write_offset, data, first_part); ++ memcpy_toio(desc_virt, data + first_part, data_len - first_part); + } ++ mmbi_update_wr_ptr(mmbi->desc_virt + write_ptr, total_len, buf_size); ++ return data_len; ++} + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg |= ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++static int mmbi_misc_open(struct inode *inode, struct file *file) ++{ ++ struct miscdevice *miscdev = file->private_data; ++ struct mmbi_chan_priv *priv = container_of(miscdev, struct mmbi_chan_priv, ++ miscdev); ++ struct mmbi_chan_desc *chan_desc = priv->chan; + -+ platform_set_drvdata(pdev, espi); ++ file->private_data = chan_desc; ++ mmbi_channel_state_update(chan_desc, chan_desc->mmbi->desc_virt); ++ mmbi_channel_start_polling(chan_desc); ++ return 0; ++} + -+ dev_info(dev, "module loaded\n"); ++static int mmbi_misc_release(struct inode *inode, struct file *file) ++{ ++ struct mmbi_chan_desc *chan_desc = file->private_data; + ++ mmbi_channel_stop_polling(chan_desc); + return 0; ++} + -+err_remove_flash: -+ ast2700_espi_flash_remove(espi); -+err_remove_oob: -+ ast2700_espi_oob_remove(espi); -+err_remove_vw: -+ ast2700_espi_vw_remove(espi); -+err_remove_perif: -+ ast2700_espi_perif_remove(espi); ++static ssize_t mmbi_misc_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ struct mmbi_chan_desc *chan_desc = file->private_data; ++ ssize_t ret; ++ void *kbuf; + -+ return rc; ++ if (count == 0) ++ return 0; ++ ++ kbuf = kmalloc(count, GFP_KERNEL); ++ if (!kbuf) ++ return -ENOMEM; ++ ++ spin_lock(&chan_desc->priv->rx_lock); ++ chan_desc->priv->rx_ready = false; ++ ret = mmbi_read(chan_desc, kbuf, count); ++ spin_unlock(&chan_desc->priv->rx_lock); ++ if (ret > 0) { ++ if (copy_to_user(buf, kbuf, ret)) { ++ pr_err("%s: chan %u copy %zd bytes to user failed\n", ++ __func__, chan_desc->index, ret); ++ ret = -EFAULT; ++ } ++ } else { ++ pr_err("%s: read failed for chan %u ret %zd\n", __func__, chan_desc->index, ret); ++ } ++ kfree(kbuf); ++ return ret; +} + -+static void ast2700_espi_remove(struct platform_device *pdev) ++static ssize_t mmbi_misc_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) +{ -+ struct ast2700_espi *espi; -+ struct device *dev; -+ uint32_t reg; -+ int rc; ++ struct mmbi_chan_desc *chan_desc = file->private_data; ++ ssize_t ret; ++ void *kbuf; + -+ dev = &pdev->dev; ++ if (count == 0) ++ return 0; + -+ espi = platform_get_drvdata(pdev); ++ kbuf = memdup_user(buf, count); ++ if (IS_ERR(kbuf)) ++ return PTR_ERR(kbuf); + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++ /* currently only MCTP defined in the spec */ ++ spin_lock(&chan_desc->priv->tx_lock); ++ ret = mmbi_write(chan_desc, kbuf, count, MMBI_PROTOCOL_MCTP); ++ spin_unlock(&chan_desc->priv->tx_lock); ++ kfree(kbuf); ++ return ret; ++} + -+ rc = ast2700_espi_perif_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++static __poll_t mmbi_misc_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ struct mmbi_chan_desc *chan_desc = file->private_data; ++ struct mmbi_ins_desc *mmbi = chan_desc->mmbi; ++ __poll_t ret, requested_events; + -+ rc = ast2700_espi_vw_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ ret = 0; ++ requested_events = poll_requested_events(pt); ++ mmbi_channel_state_update(chan_desc, mmbi->desc_virt); + -+ rc = ast2700_espi_oob_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ if (chan_desc->priv->state != NORMAL_RUNTIME && chan_desc->priv->state != RESET_REQ_BY_BMC) { ++ pr_info("%s: chan %u invalid state 0x%x, not ready for polling\n", ++ __func__, chan_desc->index, chan_desc->priv->state); ++ return ret; ++ } + -+ rc = ast2700_espi_flash_remove(espi); -+ if (rc) -+ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++ if (requested_events & POLL_IN) ++ poll_wait(file, &chan_desc->priv->rx_wait, pt); ++ if (requested_events & POLL_OUT) ++ poll_wait(file, &chan_desc->priv->tx_wait, pt); ++ ++ if (chan_desc->priv->rx_ready) ++ ret |= POLL_IN | POLLRDNORM; ++ if (chan_desc->priv->tx_ready) ++ ret |= POLL_OUT | POLLWRNORM; ++ ++ return ret; +} + -+static const struct of_device_id ast2700_espi_of_matches[] = { -+ { .compatible = "aspeed,ast2700-espi" }, -+ { }, ++static const struct file_operations mmbi_fops = { ++ .owner = THIS_MODULE, ++ .open = mmbi_misc_open, ++ .read = mmbi_misc_read, ++ .write = mmbi_misc_write, ++ .poll = mmbi_misc_poll, ++ .release = mmbi_misc_release, +}; + -+static struct platform_driver ast2700_espi_driver = { -+ .driver = { -+ .name = "ast2700-espi", -+ .of_match_table = ast2700_espi_of_matches, -+ }, -+ .probe = ast2700_espi_probe, -+ .remove = ast2700_espi_remove, -+}; ++static void mmbi_channel_refresh_locked(struct mmbi_chan_desc *chan_desc) ++{ ++ if (chan_desc->mmbi->role == MMBI_ROLE_BMC) ++ mmbi_channel_irq_bmc(chan_desc); ++ else ++ mmbi_channel_irq_host(chan_desc); ++} ++ ++#if IS_ENABLED(CONFIG_MCTP) ++static void mmbi_mctp_update_queue_state(struct mmbi_chan_desc *chan_desc) ++{ ++ struct net_device *ndev = chan_desc->priv->ndev; ++ ++ if (!ndev || !netif_running(ndev)) ++ return; ++ ++ if (chan_desc->priv->state == NORMAL_RUNTIME) { ++ netif_carrier_on(ndev); ++ if (chan_desc->priv->tx_ready) ++ netif_wake_queue(ndev); ++ else ++ netif_stop_queue(ndev); ++ } else { ++ netif_carrier_off(ndev); ++ netif_stop_queue(ndev); ++ } ++} ++ ++static void mmbi_mctp_handle_rx(struct mmbi_chan_desc *chan_desc) ++{ ++ struct net_device *ndev = chan_desc->priv->ndev; ++ u8 *tmp_buf; ++ ++ if (!ndev || !netif_running(ndev)) ++ goto out; ++ ++ tmp_buf = kmalloc(MMBI_MCTP_RX_BUF_SIZE, GFP_KERNEL); ++ if (!tmp_buf) { ++ ndev->stats.rx_dropped++; ++ goto out; ++ } ++ ++ while (netif_running(ndev)) { ++ struct sk_buff *skb; ++ struct mctp_skb_cb *cb; ++ int ret; ++ ++ if (!READ_ONCE(chan_desc->priv->rx_ready)) ++ break; ++ ++ spin_lock(&chan_desc->priv->rx_lock); ++ spin_lock(&chan_desc->priv->tx_lock); ++ ret = mmbi_read(chan_desc, tmp_buf, MMBI_MCTP_RX_BUF_SIZE); ++ mmbi_channel_refresh_locked(chan_desc); ++ spin_unlock(&chan_desc->priv->tx_lock); ++ spin_unlock(&chan_desc->priv->rx_lock); ++ ++ if (ret <= 0) { ++ if (ret < 0) ++ ndev->stats.rx_dropped++; ++ break; ++ } ++ ++ skb = netdev_alloc_skb(ndev, ret); ++ if (!skb) { ++ ndev->stats.rx_dropped++; ++ break; ++ } ++ ++ skb_put_data(skb, tmp_buf, ret); ++ skb->protocol = htons(ETH_P_MCTP); ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ ++ cb = __mctp_cb(skb); ++ cb->halen = 0; ++ ++ netif_wake_queue(ndev); ++ ndev->stats.rx_packets++; ++ ndev->stats.rx_bytes += ret; ++ if (netif_rx(skb) == NET_RX_DROP) ++ ndev->stats.rx_dropped++; ++ } ++ ++ kfree(tmp_buf); ++out: ++ mmbi_mctp_update_queue_state(chan_desc); ++} ++ ++static netdev_tx_t mmbi_mctp_ndo_start_xmit(struct sk_buff *skb, ++ struct net_device *ndev) ++{ ++ struct mmbi_mctp_netdev *mmbi_ndev = netdev_priv(ndev); ++ struct mmbi_chan_desc *chan_desc = mmbi_ndev->chan; ++ int ret; ++ ++ spin_lock(&chan_desc->priv->rx_lock); ++ spin_lock(&chan_desc->priv->tx_lock); ++ ret = mmbi_write(chan_desc, skb->data, skb->len, MMBI_PROTOCOL_MCTP); ++ mmbi_channel_refresh_locked(chan_desc); ++ spin_unlock(&chan_desc->priv->tx_lock); ++ spin_unlock(&chan_desc->priv->rx_lock); ++ ++ if (ret == -EAGAIN) { ++ netif_stop_queue(ndev); ++ return NETDEV_TX_BUSY; ++ } + -+module_platform_driver(ast2700_espi_driver); ++ if (ret < 0) { ++ ndev->stats.tx_dropped++; ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } + -+MODULE_AUTHOR("Chia-Wei Wang "); -+MODULE_DESCRIPTION("Control of AST2700 eSPI Device"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2700-espi.h b/drivers/soc/aspeed/ast2700-espi.h ---- a/drivers/soc/aspeed/ast2700-espi.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2700-espi.h 2025-12-23 10:16:21.126032636 +0000 -@@ -0,0 +1,281 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#ifndef _AST2700_ESPI_H_ -+#define _AST2700_ESPI_H_ ++ ndev->stats.tx_packets++; ++ ndev->stats.tx_bytes += ret; ++ dev_kfree_skb_any(skb); ++ mmbi_mctp_update_queue_state(chan_desc); + -+#include -+#include "aspeed-espi-comm.h" ++ return NETDEV_TX_OK; ++} + -+/* SCU regiseters */ -+#define SCU1_DDR 0x0c8 -+#define SCU1_DDR_DIS_ESPI0_AHB BIT(0) -+#define SCU1_DDR_DIS_ESPI1_AHB BIT(1) ++static int mmbi_mctp_ndo_open(struct net_device *ndev) ++{ ++ struct mmbi_mctp_netdev *mmbi_ndev = netdev_priv(ndev); ++ struct mmbi_chan_desc *chan_desc = mmbi_ndev->chan; + -+/* global registers */ -+#define ESPI_CTRL 0x000 -+#define ESPI_STS 0x004 -+#define ESPI_INT_STS 0x008 -+#define ESPI_INT_STS_RST_DEASSERT BIT(31) -+#define ESPI_INT_STS_RST_ASSERT BIT(30) -+#define ESPI_INT_STS_CH3 BIT(3) -+#define ESPI_INT_STS_CH2 BIT(2) -+#define ESPI_INT_STS_CH1 BIT(1) -+#define ESPI_INT_STS_CH0 BIT(0) -+#define ESPI_INT_EN 0x00c -+#define ESPI_INT_EN_RST_DEASSERT BIT(31) -+#define ESPI_INT_EN_RST_ASSERT BIT(30) -+#define ESPI_DEV_ID 0x010 -+#define ESPI_CAP_GEN 0x014 -+#define ESPI_CAP_GEN_RTC_SUP BIT(29) -+#define ESPI_CAP_CH0 0x018 -+#define ESPI_CAP_CH1 0x01c -+#define ESPI_CAP_CH2 0x020 -+#define ESPI_CAP_CH3_0 0x024 -+#define ESPI_CAP_CH3_1 0x028 -+#define ESPI_DEV_STS 0x030 -+#define ESPI_DBG_CTRL 0x034 -+#define ESPI_DBG_ADDRL 0x038 -+#define ESPI_DBG_ADDRH 0x03c -+#define ESPI_DBG_CMD 0x040 -+#define ESPI_DBG_RES 0x044 -+#define ESPI_CH_ACC_CTRL 0x04c -+#define ESPI_CH_ACC_OFST1 0x050 -+#define ESPI_CH_ACC_OFST2 0x054 -+#define ESPI_WPROT0 0x0f8 -+#define ESPI_WPROT1 0x0fc ++ spin_lock(&chan_desc->priv->rx_lock); ++ spin_lock(&chan_desc->priv->tx_lock); ++ mmbi_channel_refresh_locked(chan_desc); ++ spin_unlock(&chan_desc->priv->tx_lock); ++ spin_unlock(&chan_desc->priv->rx_lock); + -+/* peripheral channel (ch0) registers */ -+#define ESPI_CH0_CTRL 0x100 -+#define ESPI_CH0_CTRL_NP_TX_RST BIT(31) -+#define ESPI_CH0_CTRL_NP_RX_RST BIT(30) -+#define ESPI_CH0_CTRL_PC_TX_RST BIT(29) -+#define ESPI_CH0_CTRL_PC_RX_RST BIT(28) -+#define ESPI_CH0_CTRL_NP_TX_DMA_EN BIT(19) -+#define ESPI_CH0_CTRL_PC_TX_DMA_EN BIT(17) -+#define ESPI_CH0_CTRL_PC_RX_DMA_EN BIT(16) -+#define ESPI_CH0_CTRL_MCYC_RD_DIS_WDT BIT(9) -+#define ESPI_CH0_CTRL_MCYC_WR_DIS_WDT BIT(8) -+#define ESPI_CH0_CTRL_MCYC_RD_DIS BIT(6) -+#define ESPI_CH0_CTRL_MCYC_WR_DIS BIT(4) -+#define ESPI_CH0_CTRL_SW_RDY BIT(1) -+#define ESPI_CH0_STS 0x104 -+#define ESPI_CH0_INT_STS 0x108 -+#define ESPI_CH0_INT_STS_PC_RX_CMPLT BIT(0) -+#define ESPI_CH0_INT_EN 0x10c -+#define ESPI_CH0_INT_EN_PC_RX_CMPLT BIT(0) -+#define ESPI_CH0_PC_RX_DMAL 0x110 -+#define ESPI_CH0_PC_RX_DMAH 0x114 -+#define ESPI_CH0_PC_RX_CTRL 0x118 -+#define ESPI_CH0_PC_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_CH0_PC_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH0_PC_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH0_PC_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH0_PC_RX_DATA 0x11c -+#define ESPI_CH0_PC_TX_DMAL 0x120 -+#define ESPI_CH0_PC_TX_DMAH 0x124 -+#define ESPI_CH0_PC_TX_CTRL 0x128 -+#define ESPI_CH0_PC_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_CH0_PC_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH0_PC_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH0_PC_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH0_PC_TX_DATA 0x12c -+#define ESPI_CH0_NP_TX_DMAL 0x130 -+#define ESPI_CH0_NP_TX_DMAH 0x134 -+#define ESPI_CH0_NP_TX_CTRL 0x138 -+#define ESPI_CH0_NP_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_CH0_NP_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH0_NP_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH0_NP_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH0_NP_TX_DATA 0x13c -+#define ESPI_CH0_MCYC0_SADDRL 0x140 -+#define ESPI_CH0_MCYC0_SADDRH 0x144 -+#define ESPI_CH0_MCYC0_TADDRL 0x148 -+#define ESPI_CH0_MCYC0_TADDRH 0x14c -+#define ESPI_CH0_MCYC0_MASKL 0x150 -+#define ESPI_CH0_MCYC0_MASKL_EN BIT(0) -+#define ESPI_CH0_MCYC0_MASKH 0x154 -+#define ESPI_CH0_MCYC1_SADDRL 0x158 -+#define ESPI_CH0_MCYC1_SADDRH 0x15c -+#define ESPI_CH0_MCYC1_TADDRL 0x160 -+#define ESPI_CH0_MCYC1_TADDRH 0x164 -+#define ESPI_CH0_MCYC1_MASKL 0x168 -+#define ESPI_CH0_MCYC1_MASKL_EN BIT(0) -+#define ESPI_CH0_MCYC1_MASKH 0x16c -+#define ESPI_CH0_WPROT0 0x1f8 -+#define ESPI_CH0_WPROT1 0x1fc ++ mmbi_channel_start_polling(chan_desc); ++ mmbi_mctp_handle_rx(chan_desc); ++ mmbi_mctp_update_queue_state(chan_desc); ++ return 0; ++} + -+/* virtual wire channel (ch1) registers */ -+#define ESPI_CH1_CTRL 0x200 -+#define ESPI_CH1_CTRL_GPIO_HW BIT(9) -+#define ESPI_CH1_CTRL_SW_RDY BIT(1) -+#define ESPI_CH1_STS 0x204 -+#define ESPI_CH1_INT_STS 0x208 -+#define ESPI_CH1_INT_STS_GPIO BIT(2) -+#define ESPI_CH1_INT_EN 0x20c -+#define ESPI_CH1_INT_EN_GPIO BIT(2) -+#define ESPI_CH1_EVT0 0x210 -+#define ESPI_CH1_EVT0_INT_EN 0x214 -+#define ESPI_CH1_EVT0_INT_T0 0x218 -+#define ESPI_CH1_EVT0_INT_T1 0x21c -+#define ESPI_CH1_EVT0_INT_T2 0x220 -+#define ESPI_CH1_EVT0_INT_STS 0x224 -+#define ESPI_CH1_EVT1 0x230 -+#define ESPI_CH1_EVT1_INT_EN 0x234 -+#define ESPI_CH1_EVT1_INT_T0 0x238 -+#define ESPI_CH1_EVT1_INT_T1 0x23c -+#define ESPI_CH1_EVT1_INT_T2 0x240 -+#define ESPI_CH1_EVT1_INT_STS 0x244 -+#define ESPI_CH1_GPIO_VAL0 0x250 -+#define ESPI_CH1_GPIO_VAL1 0x254 -+#define ESPI_CH1_GPIO_DIR0 0x258 -+#define ESPI_CH1_GPIO_DIR1 0x25c -+#define ESPI_CH1_GPIO_RSTSEL0 0x260 -+#define ESPI_CH1_GPIO_RSTSEL1 0x264 -+#define ESPI_CH1_GPIO_GRP 0x268 -+#define ESPI_CH1_GP50_DIR0 0x270 -+#define ESPI_CH1_GP50_DIR1 0x274 -+#define ESPI_CH1_GP50_VAL0 0x278 -+#define ESPI_CH1_GP50_VAL1 0x27c -+#define ESPI_CH1_SW_INT 0x280 -+#define ESPI_CH1_INT_RSTSEL0 0x284 -+#define ESPI_CH1_INT_RSTSEL1 0x288 -+#define ESPI_CH1_WPROT0 0x2f8 -+#define ESPI_CH1_WPROT1 0x2fc ++static int mmbi_mctp_ndo_stop(struct net_device *ndev) ++{ ++ struct mmbi_mctp_netdev *mmbi_ndev = netdev_priv(ndev); + -+/* out-of-band channel (ch2) registers */ -+#define ESPI_CH2_CTRL 0x300 -+#define ESPI_CH2_CTRL_TX_RST BIT(31) -+#define ESPI_CH2_CTRL_RX_RST BIT(30) -+#define ESPI_CH2_CTRL_TX_DMA_EN BIT(17) -+#define ESPI_CH2_CTRL_RX_DMA_EN BIT(16) -+#define ESPI_CH2_CTRL_SW_RDY BIT(4) -+#define ESPI_CH2_STS 0x304 -+#define ESPI_CH2_INT_STS 0x308 -+#define ESPI_CH2_INT_STS_RX_CMPLT BIT(0) -+#define ESPI_CH2_INT_EN 0x30c -+#define ESPI_CH2_INT_EN_RX_CMPLT BIT(0) -+#define ESPI_CH2_RX_DMAL 0x310 -+#define ESPI_CH2_RX_DMAH 0x314 -+#define ESPI_CH2_RX_CTRL 0x318 -+#define ESPI_CH2_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_CH2_RX_CTRL_PEC BIT(24) -+#define ESPI_CH2_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH2_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH2_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH2_RX_DATA 0x31c -+#define ESPI_CH2_TX_DMAL 0x320 -+#define ESPI_CH2_TX_DMAH 0x324 -+#define ESPI_CH2_TX_CTRL 0x328 -+#define ESPI_CH2_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_CH2_TX_CTRL_PEC BIT(24) -+#define ESPI_CH2_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH2_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH2_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH2_TX_DATA 0x32c -+#define ESPI_CH2_RX_DESC_EPTR 0x330 -+#define ESPI_CH2_RX_DESC_RPTR 0x334 -+#define ESPI_CH2_RX_DESC_RPTR_UPDATE BIT(31) -+#define ESPI_CH2_RX_DESC_RPTR_RP GENMASK(11, 0) -+#define ESPI_CH2_RX_DESC_WPTR 0x338 -+#define ESPI_CH2_RX_DESC_WPTR_VALID BIT(31) -+#define ESPI_CH2_RX_DESC_WPTR_SP GENMASK(27, 16) -+#define ESPI_CH2_RX_DESC_WPTR_WP GENMASK(11, 0) -+#define ESPI_CH2_RX_DESC_TMOUT 0x33c -+#define ESPI_CH2_TX_DESC_EPTR 0x340 -+#define ESPI_CH2_TX_DESC_RPTR 0x344 -+#define ESPI_CH2_TX_DESC_RPTR_UPT BIT(31) -+#define ESPI_CH2_TX_DESC_WPTR 0x348 -+#define ESPI_CH2_TX_DESC_WPTR_VALID BIT(31) -+#define ESPI_CH2_WPROT0 0x3f8 -+#define ESPI_CH2_WPROT1 0x3fc ++ netif_stop_queue(ndev); ++ mmbi_channel_stop_polling(mmbi_ndev->chan); ++ return 0; ++} + -+/* flash channel (ch3) registers */ -+#define ESPI_CH3_CTRL 0x400 -+#define ESPI_CH3_CTRL_TX_RST BIT(31) -+#define ESPI_CH3_CTRL_RX_RST BIT(30) -+#define ESPI_CH3_CTRL_TX_DMA_EN BIT(17) -+#define ESPI_CH3_CTRL_RX_DMA_EN BIT(16) -+#define ESPI_CH3_CTRL_EDAF_MODE GENMASK(9, 8) -+#define ESPI_CH3_CTRL_SW_RDY BIT(5) -+#define ESPI_CH3_STS 0x404 -+#define ESPI_CH3_INT_STS 0x408 -+#define ESPI_CH3_INT_STS_RX_CMPLT BIT(0) -+#define ESPI_CH3_INT_EN 0x40c -+#define ESPI_CH3_INT_EN_RX_CMPLT BIT(0) -+#define ESPI_CH3_RX_DMAL 0x410 -+#define ESPI_CH3_RX_DMAH 0x414 -+#define ESPI_CH3_RX_CTRL 0x418 -+#define ESPI_CH3_RX_CTRL_SERV_PEND BIT(31) -+#define ESPI_CH3_RX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH3_RX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH3_RX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH3_RX_DATA 0x41c -+#define ESPI_CH3_TX_DMAL 0x420 -+#define ESPI_CH3_TX_DMAH 0x424 -+#define ESPI_CH3_TX_CTRL 0x428 -+#define ESPI_CH3_TX_CTRL_TRIG_PEND BIT(31) -+#define ESPI_CH3_TX_CTRL_LEN GENMASK(23, 12) -+#define ESPI_CH3_TX_CTRL_TAG GENMASK(11, 8) -+#define ESPI_CH3_TX_CTRL_CYC GENMASK(7, 0) -+#define ESPI_CH3_TX_DATA 0x42c -+#define ESPI_CH3_EDAF_TADDRL 0x430 -+#define ESPI_CH3_EDAF_TADDRH 0x434 -+#define ESPI_CH3_EDAF_MASKL 0x438 -+#define ESPI_CH3_EDAF_MASKH 0x43c -+#define ESPI_CH3_WPROT0 0x4f8 -+#define ESPI_CH3_WPROT1 0x4fc ++static const struct net_device_ops mmbi_mctp_netdev_ops = { ++ .ndo_open = mmbi_mctp_ndo_open, ++ .ndo_stop = mmbi_mctp_ndo_stop, ++ .ndo_start_xmit = mmbi_mctp_ndo_start_xmit, ++}; + -+/* eDAF filter registers */ -+#define ESPI_EDAF_FLTR_SADDR0 0x510 -+#define ESPI_EDAF_FLTR_EADDR0 0x514 -+#define ESPI_EDAF_FLTR_SADDR1 0x518 -+#define ESPI_EDAF_FLTR_EADDR1 0x51c -+#define ESPI_EDAF_FLTR_SADDR2 0x520 -+#define ESPI_EDAF_FLTR_EADDR2 0x524 -+#define ESPI_EDAF_FLTR_SADDR3 0x528 -+#define ESPI_EDAF_FLTR_EADDR3 0x52c -+#define ESPI_EDAF_FLTR_SADDR4 0x530 -+#define ESPI_EDAF_FLTR_EADDR4 0x534 -+#define ESPI_EDAF_FLTR_SADDR5 0x538 -+#define ESPI_EDAF_FLTR_EADDR5 0x53c -+#define ESPI_EDAF_FLTR_SADDR6 0x540 -+#define ESPI_EDAF_FLTR_EADDR6 0x544 -+#define ESPI_EDAF_FLTR_SADDR7 0x548 -+#define ESPI_EDAF_FLTR_EADDR7 0x54c -+#define ESPI_EDAF_FLTR_SADDR8 0x550 -+#define ESPI_EDAF_FLTR_EADDR8 0x554 -+#define ESPI_EDAF_FLTR_SADDR9 0x558 -+#define ESPI_EDAF_FLTR_EADDR9 0x55c -+#define ESPI_EDAF_FLTR_SADDR10 0x560 -+#define ESPI_EDAF_FLTR_EADDR10 0x564 -+#define ESPI_EDAF_FLTR_SADDR11 0x568 -+#define ESPI_EDAF_FLTR_EADDR11 0x56c -+#define ESPI_EDAF_FLTR_SADDR12 0x570 -+#define ESPI_EDAF_FLTR_EADDR12 0x574 -+#define ESPI_EDAF_FLTR_SADDR13 0x578 -+#define ESPI_EDAF_FLTR_EADDR13 0x57c -+#define ESPI_EDAF_FLTR_SADDR14 0x580 -+#define ESPI_EDAF_FLTR_EADDR14 0x584 -+#define ESPI_EDAF_FLTR_SADDR15 0x588 -+#define ESPI_EDAF_FLTR_EADDR15 0x58c -+#define ESPI_EDAF_WPROT0 0x5f8 -+#define ESPI_EDAF_WPROT1 0x5fc ++static void mmbi_mctp_net_setup(struct net_device *ndev) ++{ ++ ndev->type = ARPHRD_MCTP; ++ ndev->flags = IFF_NOARP; ++ ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; ++ ndev->hard_header_len = 0; ++ ndev->addr_len = 0; ++ ndev->netdev_ops = &mmbi_mctp_netdev_ops; ++} + -+/* MMBI registers */ -+#define ESPI_MMBI_CTRL 0x800 -+#define ESPI_MMBI_CTRL_INST_NUM GENMASK(6, 4) -+#define ESPI_MMBI_CTRL_EN BIT(0) -+#define ESPI_MMBI_INT_STS 0x808 -+#define ESPI_MMBI_INT_EN 0x80c -+#define ESPI_MMBI_HOST_RWP(x) (0x810 + ((x) << 3)) ++static int mmbi_channel_init_mctp_netdev(struct mmbi_chan_desc *chan_desc) ++{ ++ struct mmbi_ins_desc *mmbi = chan_desc->mmbi; ++ struct mmbi_mctp_netdev *mmbi_ndev; ++ struct net_device *ndev; ++ char ifname[IFNAMSIZ]; ++ u32 max_mtu; ++ int ret; + -+enum ast2700_edaf_mode { -+ EDAF_MODE_MIX, -+ EDAF_MODE_SW, -+ EDAF_MODE_HW, -+ EDAF_MODES, -+}; ++ max_mtu = min(chan_desc->b2h_l, chan_desc->h2b_l); ++ if (max_mtu <= MMBI_PKT_HDR_SIZE || ++ max_mtu - MMBI_PKT_HDR_SIZE < MMBI_MCTP_MIN_MTU) { ++ dev_err(mmbi->dev, ++ "channel %u MMBI buffers are too small for MCTP netdev\n", ++ chan_desc->index); ++ return -EINVAL; ++ } + -+#endif -diff --git a/drivers/soc/aspeed/ast2700-otp.c b/drivers/soc/aspeed/ast2700-otp.c ---- a/drivers/soc/aspeed/ast2700-otp.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2700-otp.c 2025-12-23 10:16:21.127032619 +0000 -@@ -0,0 +1,565 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2024 Aspeed Technology Inc. -+ */ ++ snprintf(ifname, sizeof(ifname), "mctpmm%dch%d", ++ mmbi->ins_id, chan_desc->index); ++ ndev = alloc_netdev(sizeof(*mmbi_ndev), ifname, NET_NAME_UNKNOWN, ++ mmbi_mctp_net_setup); ++ if (!ndev) ++ return -ENOMEM; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ SET_NETDEV_DEV(ndev, mmbi->dev); ++ ndev->dev.of_node = mmbi->dev->of_node; ++ ndev->min_mtu = MMBI_MCTP_MIN_MTU; ++ ndev->max_mtu = max_mtu - MMBI_PKT_HDR_SIZE; ++ ndev->mtu = ndev->max_mtu; + -+static DEFINE_SPINLOCK(otp_state_lock); ++ mmbi_ndev = netdev_priv(ndev); ++ mmbi_ndev->chan = chan_desc; ++ chan_desc->priv->ndev = ndev; + -+/*********************** -+ * * -+ * OTP regs definition * -+ * * -+ ***********************/ -+#define OTP_REG_SIZE 0x200 ++ ret = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_MMBI); ++ if (ret) { ++ dev_err(mmbi->dev, ++ "failed to register MCTP netdev for channel %u: %d\n", ++ chan_desc->index, ret); ++ chan_desc->priv->ndev = NULL; ++ free_netdev(ndev); ++ return ret; ++ } + -+#define OTP_PASSWD 0x349fe38a -+#define OTP_CMD_READ 0x23b1e361 -+#define OTP_CMD_PROG 0x23b1e364 -+#define OTP_CMD_PROG_MULTI 0x23b1e365 -+#define OTP_CMD_CMP 0x23b1e363 -+#define OTP_CMD_BIST 0x23b1e368 ++ dev_info(mmbi->dev, "registered MCTP netdev %s for channel %u\n", ++ ndev->name, chan_desc->index); + -+#define OTP_CMD_OFFSET 0x20 -+#define OTP_MASTER OTP_M0 ++ return 0; ++} + -+#define OTP_KEY 0x0 -+#define OTP_CMD (OTP_MASTER * OTP_CMD_OFFSET + 0x4) -+#define OTP_WDATA_0 (OTP_MASTER * OTP_CMD_OFFSET + 0x8) -+#define OTP_WDATA_1 (OTP_MASTER * OTP_CMD_OFFSET + 0xc) -+#define OTP_WDATA_2 (OTP_MASTER * OTP_CMD_OFFSET + 0x10) -+#define OTP_WDATA_3 (OTP_MASTER * OTP_CMD_OFFSET + 0x14) -+#define OTP_STATUS (OTP_MASTER * OTP_CMD_OFFSET + 0x18) -+#define OTP_ADDR (OTP_MASTER * OTP_CMD_OFFSET + 0x1c) -+#define OTP_RDATA (OTP_MASTER * OTP_CMD_OFFSET + 0x20) ++static void mmbi_channel_remove_mctp_netdev(struct mmbi_chan_desc *chan_desc) ++{ ++ struct net_device *ndev = chan_desc->priv->ndev; + -+#define OTP_DBG00 0x0C4 -+#define OTP_DBG01 0x0C8 -+#define OTP_MASTER_PID 0x0D0 -+#define OTP_ECC_EN 0x0D4 -+#define OTP_CMD_LOCK 0x0D8 -+#define OTP_SW_RST 0x0DC -+#define OTP_SLV_ID 0x0E0 -+#define OTP_PMC_CQ 0x0E4 -+#define OTP_FPGA 0x0EC -+#define OTP_CLR_FPGA 0x0F0 -+#define OTP_REGION_ROM_PATCH 0x100 -+#define OTP_REGION_OTPCFG 0x104 -+#define OTP_REGION_OTPSTRAP 0x108 -+#define OTP_REGION_OTPSTRAP_EXT 0x10C -+#define OTP_REGION_SECURE0 0x120 -+#define OTP_REGION_SECURE0_RANGE 0x124 -+#define OTP_REGION_SECURE1 0x128 -+#define OTP_REGION_SECURE1_RANGE 0x12C -+#define OTP_REGION_SECURE2 0x130 -+#define OTP_REGION_SECURE2_RANGE 0x134 -+#define OTP_REGION_SECURE3 0x138 -+#define OTP_REGION_SECURE3_RANGE 0x13C -+#define OTP_REGION_USR0 0x140 -+#define OTP_REGION_USR0_RANGE 0x144 -+#define OTP_REGION_USR1 0x148 -+#define OTP_REGION_USR1_RANGE 0x14C -+#define OTP_REGION_USR2 0x150 -+#define OTP_REGION_USR2_RANGE 0x154 -+#define OTP_REGION_USR3 0x158 -+#define OTP_REGION_USR3_RANGE 0x15C -+#define OTP_REGION_CALIPTRA_0 0x160 -+#define OTP_REGION_CALIPTRA_0_RANGE 0x164 -+#define OTP_REGION_CALIPTRA_1 0x168 -+#define OTP_REGION_CALIPTRA_1_RANGE 0x16C -+#define OTP_REGION_CALIPTRA_2 0x170 -+#define OTP_REGION_CALIPTRA_2_RANGE 0x174 -+#define OTP_REGION_CALIPTRA_3 0x178 -+#define OTP_REGION_CALIPTRA_3_RANGE 0x17C -+#define OTP_RBP_SOC_SVN 0x180 -+#define OTP_RBP_SOC_KEYRETIRE 0x184 -+#define OTP_RBP_CALIP_SVN 0x188 -+#define OTP_RBP_CALIP_KEYRETIRE 0x18C -+#define OTP_PUF 0x1A0 -+#define OTP_MASTER_ID 0x1B0 -+#define OTP_MASTER_ID_EXT 0x1B4 -+#define OTP_R_MASTER_ID 0x1B8 -+#define OTP_R_MASTER_ID_EXT 0x1BC -+#define OTP_SOC_ECCKEY 0x1C0 -+#define OTP_SEC_BOOT_EN 0x1C4 -+#define OTP_SOC_KEY 0x1C8 -+#define OTP_CALPITRA_MANU_KEY 0x1CC -+#define OTP_CALPITRA_OWNER_KEY 0x1D0 -+#define OTP_FW_ID_LSB 0x1D4 -+#define OTP_FW_ID_MSB 0x1D8 -+#define OTP_CALIP_FMC_SVN 0x1DC -+#define OTP_CALIP_RUNTIME_SVN0 0x1E0 -+#define OTP_CALIP_RUNTIME_SVN1 0x1E4 -+#define OTP_CALIP_RUNTIME_SVN2 0x1E8 -+#define OTP_CALIP_RUNTIME_SVN3 0x1EC -+#define OTP_SVN_WLOCK 0x1F0 -+#define OTP_INTR_EN 0x200 -+#define OTP_INTR_STS 0x204 -+#define OTP_INTR_MID 0x208 -+#define OTP_INTR_FUNC_INFO 0x20C -+#define OTP_INTR_M_INFO 0x210 -+#define OTP_INTR_R_INFO 0x214 ++ if (!ndev) ++ return; + -+#define OTP_PMC 0x400 -+#define OTP_DAP 0x500 ++ mctp_unregister_netdev(ndev); ++ free_netdev(ndev); ++ chan_desc->priv->ndev = NULL; ++} ++#else ++static void mmbi_mctp_handle_rx(struct mmbi_chan_desc *chan_desc) ++{ ++} + -+/* OTP status: [0] */ -+#define OTP_STS_IDLE 0x0 -+#define OTP_STS_BUSY 0x1 ++static int mmbi_channel_init_mctp_netdev(struct mmbi_chan_desc *chan_desc) ++{ ++ struct mmbi_ins_desc *mmbi = chan_desc->mmbi; + -+/* OTP cmd status: [7:4] */ -+#define OTP_GET_CMD_STS(x) (((x) & 0xF0) >> 4) -+#define OTP_STS_PASS 0x0 -+#define OTP_STS_FAIL 0x1 -+#define OTP_STS_CMP_FAIL 0x2 -+#define OTP_STS_REGION_FAIL 0x3 -+#define OTP_STS_MASTER_FAIL 0x4 ++ dev_err(mmbi->dev, "MCTP support is not reachable for MMBI netdev mode\n"); ++ return -EOPNOTSUPP; ++} + -+/* OTP ECC EN */ -+#define ECC_ENABLE 0x1 -+#define ECC_DISABLE 0x0 -+#define ECCBRP_EN BIT(0) ++static void mmbi_channel_remove_mctp_netdev(struct mmbi_chan_desc *chan_desc) ++{ ++} ++#endif + -+#define ROM_REGION_START_ADDR 0x0 -+#define ROM_REGION_END_ADDR 0x3e0 -+#define RBP_REGION_START_ADDR ROM_REGION_END_ADDR -+#define RBP_REGION_END_ADDR 0x400 -+#define CONF_REGION_START_ADDR RBP_REGION_END_ADDR -+#define CONF_REGION_END_ADDR 0x420 -+#define STRAP_REGION_START_ADDR CONF_REGION_END_ADDR -+#define STRAP_REGION_END_ADDR 0x430 -+#define STRAPEXT_REGION_START_ADDR STRAP_REGION_END_ADDR -+#define STRAPEXT_REGION_END_ADDR 0x440 -+#define USER_REGION_START_ADDR STRAPEXT_REGION_END_ADDR -+#define USER_REGION_END_ADDR 0x1000 -+#define SEC_REGION_START_ADDR USER_REGION_END_ADDR -+#define SEC_REGION_END_ADDR 0x1c00 -+#define CAL_REGION_START_ADDR SEC_REGION_END_ADDR -+#define CAL_REGION_END_ADDR 0x1f80 -+#define SW_PUF_REGION_START_ADDR CAL_REGION_END_ADDR -+#define SW_PUF_REGION_END_ADDR 0x1fc0 -+#define HW_PUF_REGION_START_ADDR SW_PUF_REGION_END_ADDR -+#define HW_PUF_REGION_END_ADDR 0x2000 ++static int mmbi_channel_init_miscdev(struct mmbi_chan_desc *chan_desc) ++{ ++ struct mmbi_ins_desc *mmbi = chan_desc->mmbi; ++ int ret; + -+#define OTP_MEMORY_SIZE (HW_PUF_REGION_END_ADDR * 2) ++ chan_desc->priv->miscdev.name = ++ devm_kasprintf(mmbi->dev, GFP_KERNEL, "mmbi%d-ch%d", ++ mmbi->ins_id, chan_desc->index); + -+#define OTP_TIMEOUT_US 10000 ++ if (!chan_desc->priv->miscdev.name) { ++ pr_err("%s: failed to allocate misc device name for chan %u\n", ++ __func__, chan_desc->index); ++ return -ENOMEM; ++ } ++ chan_desc->priv->miscdev.minor = MISC_DYNAMIC_MINOR; ++ chan_desc->priv->miscdev.fops = &mmbi_fops; ++ chan_desc->priv->miscdev.parent = mmbi->dev; + -+/* OTPSTRAP */ -+#define OTPSTRAP0_ADDR STRAP_REGION_START_ADDR -+#define OTPSTRAP14_ADDR (OTPSTRAP0_ADDR + 0xe) ++ ret = misc_register(&chan_desc->priv->miscdev); ++ if (ret) ++ pr_err("%s: failed to register misc device for chan %u\n", ++ __func__, chan_desc->index); + -+#define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) -+#define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff) -+#define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff) -+#define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff) -+#define OTPTOOL_COMPT_VERSION 2 ++ return ret; ++} + -+enum otp_error_code { -+ OTP_SUCCESS, -+ OTP_READ_FAIL, -+ OTP_PROG_FAIL, -+ OTP_CMP_FAIL, -+}; ++static void mmbi_channel_remove_miscdev(struct mmbi_chan_desc *chan_desc) ++{ ++ misc_deregister(&chan_desc->priv->miscdev); ++} + -+enum aspeed_otp_master_id { -+ OTP_M0 = 0, -+ OTP_M1, -+ OTP_M2, -+ OTP_M3, -+ OTP_M4, -+ OTP_M5, -+ OTP_MID_MAX, -+}; ++static int mmbi_channel_init_user_interface(struct mmbi_chan_desc *chan_desc) ++{ ++ switch (chan_desc->app_interface) { ++ case MMBI_APP_INTF_MCTP_NETDEV: ++ return mmbi_channel_init_mctp_netdev(chan_desc); ++ case MMBI_APP_INTF_IOCTL: ++ default: ++ return mmbi_channel_init_miscdev(chan_desc); ++ } ++} + -+struct aspeed_otp { -+ struct miscdevice miscdev; -+ struct device *dev; -+ void __iomem *base; -+ u32 chip_revid0; -+ u32 chip_revid1; -+ bool is_open; -+ int gbl_ecc_en; -+ u8 *data; -+}; ++static void mmbi_channel_remove_user_interface(struct mmbi_chan_desc *chan_desc) ++{ ++ switch (chan_desc->app_interface) { ++ case MMBI_APP_INTF_MCTP_NETDEV: ++ mmbi_channel_remove_mctp_netdev(chan_desc); ++ break; ++ case MMBI_APP_INTF_IOCTL: ++ default: ++ mmbi_channel_remove_miscdev(chan_desc); ++ break; ++ } ++} ++ ++static int mmbi_instance_init_user_interface(struct mmbi_ins_desc *mmbi) ++{ ++ int i, ret; + -+enum otp_ioctl_cmds { -+ GET_ECC_STATUS = 1, -+ SET_ECC_ENABLE, -+}; ++ for (i = 0; i < mmbi->num_of_channels; i++) { ++ ret = mmbi_channel_init_user_interface(&mmbi->chan_desc[i]); ++ if (ret) ++ goto err_remove_interfaces; ++ } + -+enum otp_ecc_codes { -+ OTP_ECC_MISMATCH = -1, -+ OTP_ECC_DISABLE = 0, -+ OTP_ECC_ENABLE = 1, -+}; ++ return 0; + -+static void otp_unlock(struct device *dev) -+{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++err_remove_interfaces: ++ while (i > 0) { ++ i--; ++ mmbi_channel_remove_user_interface(&mmbi->chan_desc[i]); ++ } + -+ writel(OTP_PASSWD, ctx->base + OTP_KEY); ++ return ret; +} + -+static void otp_lock(struct device *dev) ++static void mmbi_instance_remove_user_interface(struct mmbi_ins_desc *mmbi) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ int i; + -+ writel(0x1, ctx->base + OTP_KEY); ++ for (i = 0; i < mmbi->num_of_channels; i++) ++ mmbi_channel_remove_user_interface(&mmbi->chan_desc[i]); +} + -+static int wait_complete(struct device *dev) ++static void mmbi_channel_poll_handler(struct work_struct *work) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); -+ int ret; -+ u32 val; ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct mmbi_chan_priv *priv = container_of(dwork, struct mmbi_chan_priv, poll_work); ++ struct mmbi_chan_desc *chan_desc = priv->chan; ++ struct mmbi_ins_desc *mmbi = chan_desc->mmbi; ++ u8 __iomem *desc_virt = mmbi->desc_virt; + -+ ret = readl_poll_timeout(ctx->base + OTP_STATUS, val, (val == 0x0), -+ 1, OTP_TIMEOUT_US); -+ if (ret) -+ dev_warn(dev, "timeout. sts:0x%x\n", val); ++ u32 state_location, read_ptr, write_ptr; + -+ return ret; -+} ++ state_location = (mmbi->role == MMBI_ROLE_BMC) ? chan_desc->buffer_desc.h_rws_p : ++ chan_desc->buffer_desc.h_ros_p; + -+static int otp_read_data(struct aspeed_otp *ctx, u32 offset, u16 *data) -+{ -+ struct device *dev = ctx->dev; -+ int ret; ++ write_ptr = ioread32(desc_virt + state_location); ++ read_ptr = ioread32(desc_virt + state_location + sizeof(u32)); + -+ writel(ctx->gbl_ecc_en, ctx->base + OTP_ECC_EN); -+ writel(offset, ctx->base + OTP_ADDR); -+ writel(OTP_CMD_READ, ctx->base + OTP_CMD); -+ ret = wait_complete(dev); -+ if (ret) -+ return OTP_READ_FAIL; ++ if (write_ptr != chan_desc->priv->write_ptr || read_ptr != chan_desc->priv->read_ptr) { ++ chan_desc->priv->write_ptr = write_ptr; ++ chan_desc->priv->read_ptr = read_ptr; + -+ data[0] = readl(ctx->base + OTP_RDATA); ++ spin_lock(&chan_desc->priv->rx_lock); ++ spin_lock(&chan_desc->priv->tx_lock); ++ mmbi_channel_refresh_locked(chan_desc); ++ spin_unlock(&chan_desc->priv->tx_lock); ++ spin_unlock(&chan_desc->priv->rx_lock); ++ ++ } ++ ++ if (chan_desc->app_interface == MMBI_APP_INTF_MCTP_NETDEV) { ++ mmbi_mctp_handle_rx(chan_desc); ++ } else { ++ if (chan_desc->priv->rx_ready) ++ wake_up_interruptible(&chan_desc->priv->rx_wait); ++ if (chan_desc->priv->tx_ready) ++ wake_up_interruptible(&chan_desc->priv->tx_wait); ++ } ++ ++ /* Reschedule the work */ ++ schedule_delayed_work(&chan_desc->priv->poll_work, msecs_to_jiffies(chan_desc->poll_interval_ms)); ++} + ++static int mmbi_instance_init_channel_priv(struct mmbi_ins_desc *mmbi) ++{ ++ int i; ++ struct mmbi_chan_desc *chan_desc; ++ ++ for (i = 0; i < mmbi->num_of_channels; i++) { ++ chan_desc = &mmbi->chan_desc[i]; ++ INIT_DELAYED_WORK(&chan_desc->priv->poll_work, mmbi_channel_poll_handler); ++ spin_lock_init(&chan_desc->priv->rx_lock); ++ spin_lock_init(&chan_desc->priv->tx_lock); ++ init_waitqueue_head(&chan_desc->priv->rx_wait); ++ init_waitqueue_head(&chan_desc->priv->tx_wait); ++ chan_desc->priv->tx_ready = true; ++ chan_desc->priv->rx_ready = false; ++ chan_desc->priv->read_ptr = 0; ++ chan_desc->priv->write_ptr = 0; ++ chan_desc->priv->running = false; ++ if (chan_desc->poll_interval_ms == 0) ++ chan_desc->poll_interval_ms = MMBI_POLL_INTERVAL_MS; ++ chan_desc->priv->ndev = NULL; ++ } + return 0; +} + -+static int otp_prog_data(struct aspeed_otp *ctx, u32 offset, u16 data) ++int mmbi_channel_avail_length(u8 __iomem *read_structure, ++ u8 __iomem *write_structure, u32 buf_size) +{ -+ struct device *dev = ctx->dev; -+ int ret; ++ u32 __read_offset = ioread32be(read_structure + sizeof(u32)); ++ u32 __write_offset = ioread32be(write_structure); + -+ writel(ctx->gbl_ecc_en, ctx->base + OTP_ECC_EN); -+ writel(offset, ctx->base + OTP_ADDR); -+ writel(data, ctx->base + OTP_WDATA_0); -+ writel(OTP_CMD_PROG, ctx->base + OTP_CMD); -+ ret = wait_complete(dev); -+ if (ret) -+ return OTP_PROG_FAIL; ++ __read_offset = MMBI_PTR_ADDR_ALIGN(be32_to_cpu(__read_offset)); ++ __write_offset = MMBI_PTR_ADDR_ALIGN(be32_to_cpu(__write_offset)); + -+ return 0; ++ return (__write_offset >= __read_offset) ? ++ (buf_size - __write_offset + __read_offset) : ++ (__read_offset - __write_offset); +} ++EXPORT_SYMBOL_GPL(mmbi_channel_avail_length); + -+static int otp_prog_multi_data(struct aspeed_otp *ctx, u32 offset, u32 *data, int count) ++int mmbi_channel_unhandled_length(u8 __iomem *read_structure, ++ u8 __iomem *write_structure, u32 buf_size) +{ -+ struct device *dev = ctx->dev; -+ int ret; ++ u32 __read_offset = ioread32be(read_structure + sizeof(u32)); ++ u32 __write_offset = ioread32be(write_structure); + -+ writel(ctx->gbl_ecc_en, ctx->base + OTP_ECC_EN); -+ writel(offset, ctx->base + OTP_ADDR); -+ for (int i = 0; i < count; i++) -+ writel(data[i], ctx->base + OTP_WDATA_0 + 4 * i); ++ __read_offset = MMBI_PTR_ADDR_ALIGN(be32_to_cpu(__read_offset)); ++ __write_offset = MMBI_PTR_ADDR_ALIGN(be32_to_cpu(__write_offset)); ++ return (__write_offset >= __read_offset) ? ++ (__write_offset - __read_offset) : ++ (buf_size - __read_offset + __write_offset); ++} ++EXPORT_SYMBOL_GPL(mmbi_channel_unhandled_length); + -+ writel(OTP_CMD_PROG_MULTI, ctx->base + OTP_CMD); -+ ret = wait_complete(dev); -+ if (ret) -+ return OTP_PROG_FAIL; ++void mmbi_channel_state_update(struct mmbi_chan_desc *chan, u8 __iomem *desc_virt) ++{ ++ u8 __iomem *host_rws_vmem; ++ u8 __iomem *host_ros_vmem; ++ u8 host_rws_val; ++ u8 host_ros_val; ++ struct mmbi_buf_vpscb *buf_desc; ++ enum mmbi_state prev_state; + -+ return 0; ++ if (chan->buffer_type == MMBI_BUFFER_TYPE_VPSCB) { ++ prev_state = chan->priv->state; ++ buf_desc = &chan->buffer_desc; ++ host_rws_vmem = desc_virt + buf_desc->h_rws_p; ++ host_ros_vmem = desc_virt + buf_desc->h_ros_p; ++ host_rws_val = ioread8(host_rws_vmem); ++ host_ros_val = ioread8(host_ros_vmem); ++ chan->priv->state = (MMBI_STATE_GET_IF_UP(host_ros_val) << 2) | ++ (MMBI_STATE_GET_RST(host_ros_val) << 2) | ++ MMBI_STATE_GET_IF_UP(host_rws_val) | ++ MMBI_STATE_GET_RST(host_rws_val); ++ ++ chan->priv->peer_ready = (chan->mmbi->role == MMBI_ROLE_BMC) ? ++ mmbi_get_ready(host_rws_vmem) : ++ mmbi_get_ready(host_ros_vmem); ++ } else { ++ pr_err("\t%s: unsupported buffer type %d\n", ++ __func__, chan->buffer_type); ++ chan->priv->state = POWER_UP_OR_ERROR; ++ } +} ++EXPORT_SYMBOL_GPL(mmbi_channel_state_update); + -+static int aspeed_otp_read(struct aspeed_otp *ctx, int offset, -+ void *buf, int size) ++int mmbi_instance_init(struct mmbi_ins_desc *mmbi) +{ -+ struct device *dev = ctx->dev; -+ u16 *data = buf; -+ int ret; ++ int rc, i; + -+ otp_unlock(dev); -+ for (int i = 0; i < size; i++) { -+ ret = otp_read_data(ctx, offset + i, data + i); -+ if (ret) { -+ dev_warn(ctx->dev, "read failed\n"); -+ break; -+ } ++ if (!mmbi) { ++ rc = -EINVAL; ++ goto out_fail; + } + -+ otp_lock(dev); -+ return ret; -+} ++ if (mmbi->role == MMBI_ROLE_BMC) { ++ if (mmbi->mmbi_version != MMBI_VERSION_1_0 && ++ mmbi->mmbi_version != MMBI_VERSION_1_1) { ++ rc = -EINVAL; ++ goto out_fail; ++ } ++ } + -+static int aspeed_otp_write(struct aspeed_otp *ctx, int offset, -+ const void *buf, int size) -+{ -+ struct device *dev = ctx->dev; -+ u32 *data32 = (u32 *)buf; -+ u16 *data = (u16 *)buf; -+ int ret; ++ mmbi->ins_id = ida_alloc(&mmbi_ida, GFP_KERNEL); ++ if (mmbi->ins_id < 0) { ++ rc = mmbi->ins_id; ++ goto out_fail; ++ } + -+ otp_unlock(dev); ++ for (i = 0; i < MMBI_MAX_CHANNELS; i++) { ++ mmbi->chan_desc[i].priv = devm_kzalloc(mmbi->dev, sizeof(*mmbi->chan_desc[i].priv), GFP_KERNEL); ++ if (!mmbi->chan_desc[i].priv) { ++ rc = -ENOMEM; ++ goto out_fail; ++ } ++ mmbi->chan_desc[i].priv->chan = &mmbi->chan_desc[i]; ++ } + -+ if (size == 1) -+ ret = otp_prog_data(ctx, offset, data[0]); ++ if (mmbi->role == MMBI_ROLE_BMC) ++ rc = mmbi_instance_init_bmc(mmbi); + else -+ ret = otp_prog_multi_data(ctx, offset, data32, size / 2); ++ rc = mmbi_instance_init_host(mmbi); + -+ if (ret) -+ dev_warn(ctx->dev, "prog failed\n"); ++ if (rc) ++ goto ida_free; + -+ otp_lock(dev); -+ return ret; ++ rc = mmbi_instance_init_channel_priv(mmbi); ++ if (rc) ++ goto ida_free; ++ ++ rc = mmbi_instance_init_user_interface(mmbi); ++ if (rc) ++ goto ida_free; ++ ++ return 0; ++ ++ida_free: ++ ida_free(&mmbi_ida, mmbi->ins_id); ++out_fail: ++ pr_err("%s: failed to init MMBI instance\n", ++ __func__); ++ return rc; +} ++EXPORT_SYMBOL_GPL(mmbi_instance_init); + -+static int aspeed_otp_ecc_en(struct aspeed_otp *ctx) ++void mmbi_instance_remove(struct mmbi_ins_desc *mmbi) +{ -+ struct device *dev = ctx->dev; -+ int ret = 0; ++ int i; ++ u8 __iomem *struct_desc; + -+ /* Check ecc is already enabled */ -+ if (ctx->gbl_ecc_en == 1) -+ return 0; ++ if (!mmbi) ++ return; + -+ otp_unlock(dev); ++ for (i = 0; i < mmbi->num_of_channels; i++) ++ mmbi_channel_stop_polling(&mmbi->chan_desc[i]); + -+ /* enable cfg ecc */ -+ ret = otp_prog_data(ctx, OTPSTRAP14_ADDR, 0x1); -+ if (ret) { -+ dev_warn(dev, "%s: prog failed\n", __func__); -+ goto end; -+ } ++ mmbi_instance_remove_user_interface(mmbi); + -+ ctx->gbl_ecc_en = 1; -+end: -+ otp_lock(dev); ++ for (i = 0; i < mmbi->num_of_channels; i++) { ++ struct_desc = ++ mmbi->desc_virt + ++ (mmbi->role == MMBI_ROLE_BMC ? ++ mmbi->chan_desc[i].buffer_desc.h_ros_p : ++ mmbi->chan_desc[i].buffer_desc.h_rws_p); ++ mmbi_clr_ready(struct_desc); ++ mmbi_clr_up(struct_desc); ++ } + -+ return ret; ++ ida_free(&mmbi_ida, mmbi->ins_id); +} ++EXPORT_SYMBOL_GPL(mmbi_instance_remove); +diff --git a/drivers/soc/aspeed/mmbi/aspeed-mmbi.h b/drivers/soc/aspeed/mmbi/aspeed-mmbi.h +--- a/drivers/soc/aspeed/mmbi/aspeed-mmbi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-mmbi.h 2026-09-09 15:51:44.722238011 +0000 +@@ -0,0 +1,174 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright 2026 Aspeed Technology Inc. ++ */ ++#ifndef __ASPEED_MMBI_H__ ++#define __ASPEED_MMBI_H__ + -+static long aspeed_otp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); -+ void __user *argp = (void __user *)arg; -+ struct otp_revid revid; -+ struct otp_read rdata; -+ struct otp_prog pdata; -+ int ret = 0; ++#include ++#include ++#include ++#include ++#include + -+ switch (cmd) { -+ case ASPEED_OTP_READ_DATA: -+ if (copy_from_user(&rdata, argp, sizeof(struct otp_read))) -+ return -EFAULT; ++#define MMBI_SIGNATURE "#MMBI$" ++#define MMBI_DESC_SIZE_PREFIX 8 ++#define MMBI_DESC_SIZE_CHANNEL 32 ++#define MMBI_DESC_SIZE_INTERRUPT 24 + -+ ret = aspeed_otp_read(ctx, rdata.offset, ctx->data, rdata.len); -+ if (ret) -+ return -EFAULT; ++#define MMBI_VERSION_1_0 0x01 ++#define MMBI_VERSION_1_1 0x02 ++#define MMBI_VERSION_MASK GENMASK(3, 0) ++#define MMBI_MAX_CHANNELS 7 ++#define MMBI_NOI_MASK GENMASK(6, 4) ++#define MMBI_OS_USE_MASK BIT(0) ++#define MMBI_BUF_ADDR_ALIGN(addr) (ALIGN_DOWN(addr, 8)) ++#define MMBI_BUF_TYPE_MASK GENMASK(3, 0) ++#define MMBI_INT_VAL_MASK GENMASK(3, 0) ++#define MMBI_INT_TYPE_MASK GENMASK(2, 0) ++#define MMBI_PTR_ADDR_MASK GENMASK(31, 2) ++#define MMBI_PTR_ADDR_ALIGN(addr) (ALIGN_DOWN(addr, 4)) ++#define MMBI_PKT_PADDING_MASK GENMASK(1, 0) ++#define MMBI_PKT_PROTOCOL_MASK GENMASK(3, 0) ++#define MMBI_PKT_MIN_SIZE 8 ++#define MMBI_PKT_HDR_SIZE 4 + -+ if (copy_to_user(rdata.data, ctx->data, rdata.len * 2)) -+ return -EFAULT; ++#define MMBI_STATE_RDY_MSK BIT(0) ++#define MMBI_STATE_RST_MSK BIT(0) ++#define MMBI_STATE_IF_UP_MSK BIT(1) + -+ break; ++#define MMBI_STATE_GET_RST(val) ((val) & MMBI_STATE_RST_MSK) ++#define MMBI_STATE_GET_IF_UP(val) ((val) & MMBI_STATE_IF_UP_MSK) + -+ case ASPEED_OTP_PROG_DATA: -+ if (copy_from_user(&pdata, argp, sizeof(struct otp_prog))) -+ return -EFAULT; ++#define MMBI_POLL_INTERVAL_MS 20 + -+ ret = aspeed_otp_write(ctx, pdata.w_offset, pdata.data, pdata.len); -+ break; ++static __always_inline u8 mmbi_get_ready(u8 __iomem *devm_virt) ++{ ++ return ioread8(devm_virt + sizeof(u32)) & MMBI_STATE_RDY_MSK; ++} + -+ case ASPEED_OTP_GET_ECC: -+ if (copy_to_user(argp, &ctx->gbl_ecc_en, sizeof(ctx->gbl_ecc_en))) -+ return -EFAULT; -+ break; ++static __always_inline void mmbi_set_ready(u8 __iomem *devm_virt) ++{ ++ iowrite8(ioread8(devm_virt + sizeof(u32)) | MMBI_STATE_RDY_MSK, ++ devm_virt + sizeof(u32)); ++} + -+ case ASPEED_OTP_SET_ECC: -+ ret = aspeed_otp_ecc_en(ctx); -+ break; ++static __always_inline void mmbi_clr_ready(u8 __iomem *devm_virt) ++{ ++ iowrite8(ioread8(devm_virt + sizeof(u32)) & ~MMBI_STATE_RDY_MSK, ++ devm_virt + sizeof(u32)); ++} + -+ case ASPEED_OTP_GET_REVID: -+ revid.revid0 = ctx->chip_revid0; -+ revid.revid1 = ctx->chip_revid1; -+ if (copy_to_user(argp, &revid, sizeof(struct otp_revid))) -+ return -EFAULT; -+ break; -+ default: -+ dev_warn(ctx->dev, "cmd 0x%x is not supported\n", cmd); -+ break; -+ } ++static __always_inline void mmbi_set_up(u8 __iomem *devm_virt) ++{ ++ iowrite8(ioread8(devm_virt) | MMBI_STATE_IF_UP_MSK, devm_virt); ++} + -+ return ret; ++static __always_inline void mmbi_clr_up(u8 __iomem *devm_virt) ++{ ++ iowrite8(ioread8(devm_virt) & ~MMBI_STATE_IF_UP_MSK, devm_virt); +} + -+static int aspeed_otp_ecc_init(struct device *dev) ++static __always_inline void mmbi_set_rst(u8 __iomem *devm_virt) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); -+ int ret; -+ u32 val; ++ iowrite8(ioread8(devm_virt) | MMBI_STATE_RST_MSK, devm_virt); ++} + -+ otp_unlock(dev); ++static __always_inline void mmbi_clr_rst(u8 __iomem *devm_virt) ++{ ++ iowrite8(ioread8(devm_virt) & ~MMBI_STATE_RST_MSK, devm_virt); ++} + -+ /* Check cfg_ecc_en */ -+ writel(0, ctx->base + OTP_ECC_EN); -+ writel(OTPSTRAP14_ADDR, ctx->base + OTP_ADDR); -+ writel(OTP_CMD_READ, ctx->base + OTP_CMD); -+ ret = wait_complete(dev); -+ if (ret) -+ return OTP_READ_FAIL; ++enum mmbi_role { ++ MMBI_ROLE_HOST = 0, ++ MMBI_ROLE_BMC = 1, ++}; + -+ val = readl(ctx->base + OTP_RDATA); -+ if (val & 0x1) -+ ctx->gbl_ecc_en = 0x1; -+ else -+ ctx->gbl_ecc_en = 0x0; ++enum mmbi_host_int_type { ++ MMBI_HOST_INT_NONE = 0, ++ MMBI_HOST_INT_PCIE = 1, ++ MMBI_HOST_INT_GPIO = 2, ++ MMBI_HOST_INT_ESPI_VW = 3, ++}; + -+ otp_lock(dev); ++enum mmbi_bmc_int_type { ++ MMBI_BMC_INT_NONE = 0, ++ MMBI_BMC_INT_MEM = 1, ++ MMBI_BMC_INT_INBAND = 2, ++}; + -+ return 0; -+} ++enum mmbi_state { /* B_U B_R H_U H_R */ ++ INIT_IN_PROGRESS = 0x00, /* 0 0 0 0 */ ++ INIT_COMPLETED = 0x08, /* 1 0 0 0 */ ++ NORMAL_RUNTIME = 0x0A, /* 1 0 1 0 */ ++ RESET_REQ_BY_BMC = 0x0E, /* 1 1 1 0 */ ++ RESET_REQ_BY_HOST = 0x0B, /* 1 0 1 1 */ ++ RESET_ACKED = 0x0F, /* 1 1 1 1 */ ++ TRANS_TO_INIT = 0x07, /* 0 1 1 1 */ ++ INIT_MISMATCH = 0x09, /* 1 0 0 1 */ ++ POWER_UP_OR_ERROR = 0x80000000, ++}; + -+static int aspeed_otp_open(struct inode *inode, struct file *file) -+{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++enum mmbi_buffer_type { ++ MMBI_BUFFER_TYPE_VPSCB = 0x01, ++}; + -+ spin_lock(&otp_state_lock); ++enum mmbi_multi_protocol { ++ MMBI_PROTOCOL_MCTP = 0x04, ++}; + -+ if (ctx->is_open) { -+ spin_unlock(&otp_state_lock); -+ return -EBUSY; -+ } ++enum mmbi_app_interface { ++ MMBI_APP_INTF_IOCTL = 0, ++ MMBI_APP_INTF_MCTP_NETDEV, ++}; + -+ ctx->is_open = true; ++struct mmbi_chan_priv; + -+ spin_unlock(&otp_state_lock); ++struct mmbi_buf_vpscb { ++ u32 h_ros_p; /* Host Read Pointer address offset */ ++ u32 h_rws_p; /* Host Read Write Pointer address offset */ ++ u8 host_int_val_ch; /* Host interrupt value, only used in MMBI v1.1 */ ++ u8 bmc_int_val_ch; /* Host interrupt value, only used in MMBI v1.1 */ ++}; + -+ return 0; -+} ++struct mmbi_chan_desc { ++ u32 b2h_ba_offset; /* B2H Buffer Base Address */ ++ u32 h2b_ba_offset; /* H2B Buffer Base Address */ ++ u32 b2h_l; /* B2H Buffer Length */ ++ u32 h2b_l; /* H2B Buffer Length */ ++ u8 buffer_type; /* Buffer Type defined by enum mmbi_buffer_type */ ++ u8 index; /* Channel Index filled by mmbi_instance_init */ ++ enum mmbi_app_interface app_interface; /* User interface for this channel */ ++ struct mmbi_buf_vpscb buffer_desc; /* buffer descriptor information */ ++ struct mmbi_ins_desc *mmbi; /* Back pointer to instance descriptor */ ++ struct mmbi_chan_priv *priv; /* Internal runtime state */ ++ u32 poll_interval_ms; /* polling interval in ms, default 10ms */ ++}; + -+static int aspeed_otp_release(struct inode *inode, struct file *file) -+{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++struct mmbi_ins_desc { ++ u8 __iomem *desc_virt; /* MMBI Instance Base Address */ ++ u8 mmbi_version; ++ u8 num_of_channels; /* NOI field, recording number of channels */ ++ u8 os_use; ++ u8 host_int_type; ++ u8 host_int_location; ++ u8 host_int_value; ++ u8 bmc_int_type; ++ u8 bmc_int_value; ++ u32 bmc_int_location; ++ int ins_id; ++ struct mmbi_chan_desc chan_desc[MMBI_MAX_CHANNELS]; ++ struct device *dev; ++ enum mmbi_role role; ++}; + -+ spin_lock(&otp_state_lock); ++void mmbi_channel_state_update(struct mmbi_chan_desc *chan, ++ u8 __iomem *desc_virt); ++int mmbi_channel_avail_length(u8 __iomem *read_structure, ++ u8 __iomem *write_structure, u32 buf_size); ++int mmbi_channel_unhandled_length(u8 __iomem *read_structure, ++ u8 __iomem *write_structure, u32 buf_size); ++int mmbi_instance_init(struct mmbi_ins_desc *mmbi); ++void mmbi_instance_remove(struct mmbi_ins_desc *mmbi); + -+ ctx->is_open = false; ++#endif +diff --git a/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.c b/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.c +--- a/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.c 2026-09-09 15:51:44.722238011 +0000 +@@ -0,0 +1,481 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright (C) ASPEED Technology Inc. + -+ spin_unlock(&otp_state_lock); ++#include ++#include ++#include ++#include + -+ return 0; -+} ++#include ++#include ++#include ++#include ++#include ++#include + -+static const struct file_operations otp_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = aspeed_otp_ioctl, -+ .open = aspeed_otp_open, -+ .release = aspeed_otp_release, -+}; ++#include ++#include + -+static const struct of_device_id aspeed_otp_of_matches[] = { -+ { .compatible = "aspeed,ast2700-otp" }, -+ { } ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "aspeed-pcie-mmbi.h" ++#include "aspeed-mmbi.h" ++ ++/* AST2700 E2M */ ++#define ASPEED_E2M_EVENT 0x0D0 ++#define ASPEED_E2M_EVENT_SET 0x0D4 ++#define ASPEED_E2M_EVENT_CLR 0x0D8 ++#define ASPEED_E2M_EVENT_EN 0x0DC ++#define ASPEED_E2M_ADRMAP00 0x100 ++#define ASPEED_E2M_WIRQA0 0x180 ++#define ASPEED_E2M_WIRQV0 0x1C0 ++#define ASPEED_E2M_SPROT_SIDG0 0x210 ++#define ASPEED_E2M_SPROT_CTL0 0x280 ++#define ASPEED_E2M_SPROT_ADR0 0x2C0 ++/* Value for triggering interrupt */ ++#define ASPEED_E2M_INT_VAL 0xC6 ++ ++/* AST2700 SCU */ ++#define ASPEED_SCU_DECODE_DEV BIT(18) ++#define ASPEED_SCU_INT_EN BIT(23) ++struct aspeed_platform { ++ int (*mmbi_init)(struct platform_device *pdev); +}; -+MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); + -+static int aspeed_otp_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct regmap *scu0, *scu1; -+ struct aspeed_otp *priv; -+ struct resource *res; -+ int rc; ++#define ASPEED_MMBI_APP_INTF_PROP "aspeed,mmbi-interface" + -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++struct aspeed_pcie_mmbi { ++ struct device *dev; ++ struct regmap *device; ++ struct regmap *e2m; ++ const struct aspeed_platform *platform; ++ /* E2M index */ ++ int id; ++ int pid; ++ int msi_index; ++ int scu_bar_offset; ++ int e2m_index; ++ int e2m_h2b_int; ++ int num_of_channels; ++ bool host_int_en; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); -+ return -ENOENT; ++ /* Memory Mapping */ ++ void __iomem *mem_virt; ++ dma_addr_t mem_phy; ++ phys_addr_t mem_size; ++ ++ struct mmbi_ins_desc mmbi_desc; ++}; ++ ++static const char * ++aspeed_pcie_mmbi_app_interface_name(enum mmbi_app_interface app_interface) ++{ ++ switch (app_interface) { ++ case MMBI_APP_INTF_MCTP_NETDEV: ++ return "mctp-netdev"; ++ case MMBI_APP_INTF_IOCTL: ++ default: ++ return "ioctl"; + } ++} + -+ priv->base = devm_ioremap_resource(&pdev->dev, res); -+ if (!priv->base) -+ return -EIO; ++static int aspeed_pcie_mmbi_parse_app_interface_string(struct device *dev, ++ const char *interface, ++ enum mmbi_app_interface *app_interface) ++{ ++ if (!strcmp(interface, "ioctl")) { ++ *app_interface = MMBI_APP_INTF_IOCTL; ++ return 0; ++ } + -+ scu0 = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu0"); -+ scu1 = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu1"); -+ if (IS_ERR(scu0) || IS_ERR(scu1)) { -+ dev_err(dev, "failed to find SCU regmap\n"); -+ return PTR_ERR(scu0) || PTR_ERR(scu1); ++ if (!strcmp(interface, "mctp-netdev")) { ++ *app_interface = MMBI_APP_INTF_MCTP_NETDEV; ++ return 0; + } + -+ regmap_read(scu0, 0x0, &priv->chip_revid0); -+ regmap_read(scu1, 0x0, &priv->chip_revid1); ++ dev_err(dev, "invalid %s value '%s'\n", ++ ASPEED_MMBI_APP_INTF_PROP, interface); ++ return -EINVAL; ++} + -+ priv->dev = dev; -+ dev_set_drvdata(dev, priv); ++static int aspeed_pcie_mmbi_parse_app_interface(struct device *dev, ++ struct mmbi_ins_desc *mmbi_desc) ++{ ++ int count, i, ret; + -+ /* OTP ECC init */ -+ rc = aspeed_otp_ecc_init(dev); -+ if (rc) -+ return -EIO; ++ for (i = 0; i < mmbi_desc->num_of_channels; i++) ++ mmbi_desc->chan_desc[i].app_interface = MMBI_APP_INTF_IOCTL; + -+ priv->data = kmalloc(OTP_MEMORY_SIZE, GFP_KERNEL); -+ if (!priv->data) -+ return -ENOMEM; ++ if (!of_find_property(dev->of_node, ASPEED_MMBI_APP_INTF_PROP, NULL)) ++ return 0; + -+ /* Set up the miscdevice */ -+ priv->miscdev.minor = MISC_DYNAMIC_MINOR; -+ priv->miscdev.name = "aspeed-otp"; -+ priv->miscdev.fops = &otp_fops; ++ count = of_property_count_strings(dev->of_node, ASPEED_MMBI_APP_INTF_PROP); ++ if (count < 0) { ++ dev_err(dev, "invalid %s property\n", ASPEED_MMBI_APP_INTF_PROP); ++ return count; ++ } + -+ /* Register the device */ -+ rc = misc_register(&priv->miscdev); -+ if (rc) { -+ dev_err(dev, "Unable to register device\n"); -+ return rc; ++ if (count != 1 && count != mmbi_desc->num_of_channels) { ++ dev_err(dev, "%s must contain either 1 or %u strings\n", ++ ASPEED_MMBI_APP_INTF_PROP, ++ (u32)mmbi_desc->num_of_channels); ++ return -EINVAL; + } + -+ dev_info(dev, "Aspeed OTP driver successfully registered\n"); ++ for (i = 0; i < mmbi_desc->num_of_channels; i++) { ++ const char *interface; ++ int index = count == 1 ? 0 : i; ++ ++ ret = of_property_read_string_index(dev->of_node, ++ ASPEED_MMBI_APP_INTF_PROP, ++ index, &interface); ++ if (ret) ++ return ret; ++ ++ ret = aspeed_pcie_mmbi_parse_app_interface_string(dev, interface, ++ &mmbi_desc->chan_desc[i].app_interface); ++ if (ret) ++ return ret; ++ } + + return 0; +} + -+static void aspeed_otp_remove(struct platform_device *pdev) ++/** ++ * Detailed Buffer Layout: ++ * ++ * +---------------------------------------+ ++ * | HOST READ ONLY REGION (50%) | ++ * +---------------------------------------+ ++ * | mmbi_desc | ++ * | - Size: 32 + 32*noi bytes | ++ * +---------------------------------------+ ++ * | Interrupt Region (8 bytes) | ++ * | - trigger_int (1 byte) | ++ * | - reserved (7 bytes) | ++ * +---------------------------------------+ ++ * | Channel 0: | ++ * | hos_ro (8 bytes) | ++ * | - First 8 bytes after interrupt | ++ * | b2h_buffer | ++ * | - Channel 0 B2H buffer space | ++ * +---------------------------------------+ ++ * | Channel 1: | ++ * | hos_ro (8 bytes) | ++ * | b2h_buffer | ++ * | - Channel 1 B2H buffer space | ++ * +---------------------------------------+ ++ * | ... | ++ * +---------------------------------------+ ++ * | Channel 6: | ++ * | hos_ro (8 bytes) | ++ * | b2h_buffer | ++ * | - Channel 6 B2H buffer space | ++ * +---------------------------------------+ ++ * | HOST READ/WRITE REGION (50%) | ++ * +---------------------------------------+ ++ * | Channel 0: | ++ * | hos_rw (8 bytes) | ++ * | - First 8 bytes of this region | ++ * | h2b_buffer | ++ * | - Channel 0 H2B buffer space | ++ * +---------------------------------------+ ++ * | Channel 1: | ++ * | hos_rw (8 bytes) | ++ * | h2b_buffer | ++ * | - Channel 1 H2B buffer space | ++ * +---------------------------------------+ ++ * | ... | ++ * +---------------------------------------+ ++ * | Channel 6: | ++ * | hos_rw (8 bytes) | ++ * | h2b_buffer | ++ * | - Channel 6 H2B buffer space | ++ * +---------------------------------------+ ++ */ ++static int aspeed_pcie_mmbi_init(struct aspeed_pcie_mmbi *mmbi) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); ++ struct mmbi_ins_desc *mmbi_desc = &mmbi->mmbi_desc; ++ struct mmbi_buf_vpscb *vpscb; ++ struct device *dev = mmbi->dev; ++ u32 desc_size, b2h_buf_size, h2b_buf_size; ++ int i, ret; + -+ kfree(ctx->data); -+ misc_deregister(&ctx->miscdev); -+} ++ desc_size = MMBI_DESC_SIZE_PREFIX + MMBI_DESC_SIZE_INTERRUPT + ++ MMBI_DESC_SIZE_CHANNEL * mmbi->num_of_channels + 8; + -+static struct platform_driver aspeed_otp_driver = { -+ .probe = aspeed_otp_probe, -+ .remove = aspeed_otp_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_otp_of_matches, -+ }, -+}; ++ if ((mmbi->mem_size >> 1) <= desc_size) { ++ dev_err(dev, "MMBI memory size too small for B2H buffer\n"); ++ return -EINVAL; ++ } + -+module_platform_driver(aspeed_otp_driver); ++ b2h_buf_size = ++ rounddown_pow_of_two(((mmbi->mem_size >> 1) - desc_size) / ++ mmbi->num_of_channels); ++ ++ h2b_buf_size = rounddown_pow_of_two((mmbi->mem_size >> 1) / mmbi->num_of_channels); ++ ++ mmbi_desc->desc_virt = mmbi->mem_virt; ++ mmbi_desc->mmbi_version = MMBI_VERSION_1_1; ++ mmbi_desc->os_use = 1; ++ mmbi_desc->num_of_channels = mmbi->num_of_channels; ++ mmbi_desc->host_int_type = MMBI_HOST_INT_PCIE; ++ mmbi_desc->host_int_location = mmbi->msi_index; ++ mmbi_desc->host_int_value = 0; /* cleared to 0 */ ++ mmbi_desc->bmc_int_type = MMBI_BMC_INT_INBAND; ++ mmbi_desc->bmc_int_location = 0; /* reserved */ ++ mmbi_desc->bmc_int_value = 0; /* cleared to 0 */ ++ mmbi_desc->dev = dev; ++ mmbi_desc->role = MMBI_ROLE_BMC; ++ ++ for (i = 0; i < mmbi_desc->num_of_channels; i++) { ++ vpscb = &mmbi_desc->chan_desc[i].buffer_desc; ++ vpscb->h_ros_p = desc_size + i * b2h_buf_size; ++ vpscb->h_rws_p = (mmbi->mem_size >> 1) + i * h2b_buf_size; ++ vpscb->host_int_val_ch = 0; ++ vpscb->bmc_int_val_ch = 0; ++ ++ mmbi_desc->chan_desc[i].b2h_ba_offset = vpscb->h_ros_p + 8; ++ mmbi_desc->chan_desc[i].h2b_ba_offset = vpscb->h_rws_p + 8; ++ mmbi_desc->chan_desc[i].b2h_l = b2h_buf_size - 8; ++ mmbi_desc->chan_desc[i].h2b_l = h2b_buf_size - 8; ++ // mmbi_desc->chan_desc[i].h2b_ba_offset = vpscb->h_rws_p + 16; ++ // mmbi_desc->chan_desc[i].b2h_l = 0x100; ++ // mmbi_desc->chan_desc[i].h2b_l = 0x100; ++ mmbi_desc->chan_desc[i].buffer_type = MMBI_BUFFER_TYPE_VPSCB; ++ } ++ ret = mmbi_instance_init(mmbi_desc); ++ if (ret) ++ dev_err(dev, "MMBI instance init failed: %d\n", ret); ++ ++ return ret; ++} + -+MODULE_AUTHOR("Neal Liu "); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("ASPEED OTP Driver"); -diff --git a/drivers/soc/aspeed/ast2700-rtc-over-espi.c b/drivers/soc/aspeed/ast2700-rtc-over-espi.c ---- a/drivers/soc/aspeed/ast2700-rtc-over-espi.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/ast2700-rtc-over-espi.c 2025-12-23 10:16:21.127032619 +0000 -@@ -0,0 +1,193 @@ -+// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright 2025 Aspeed Technology Inc. ++ * AST2700 PCIe MMBI (SCU & E2M) ++ * SoC | 0 | 1 | ++ * PCI class | MFD (0xFF_00_00) | MMBI (0x0C_0C_00) | ++ * Node | 0 1 | 0 | ++ * PID | 3 4 5 6 11 12 13 14 | 2 3 4 5 6 7 | ++ * E2M index | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 | ++ * BAR index | 2 3 4 5 2 3 4 5 | 0 1 2 3 4 5 | ++ * SCU BAR | 3c 4c 5c 6c 3c 4c 5c 6c | 1c 50 3c 4c 5c 6c | ++ * E2M H2B Int | 0 1 2 3 0 1 2 3 | 0 1 2 3 4 5 | (bit) + */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SYNC_INTERVAL_MS_DEFAULT 1000 -+ -+#define RTC_REG0 0x0 -+#define RTC_REG0_MINUTES_ALARM GENMASK(31, 24) -+#define RTC_REG0_MINUTES GENMASK(23, 16) -+#define RTC_REG0_SECONDS_ALARM GENMASK(15, 8) -+#define RTC_REG0_SECONDS GENMASK(7, 0) -+#define RTC_REG1 0x4 -+#define RTC_REG1_DAY_OF_MONTH GENMASK(31, 24) -+#define RTC_REG1_DAY_OF_WEEK GENMASK(23, 16) -+#define RTC_REG1_HOURS_ALARM GENMASK(15, 8) -+#define RTC_REG1_HOURS GENMASK(7, 0) -+#define RTC_REG2 0x8 -+#define RTC_REG2_YEAR GENMASK(15, 8) -+#define RTC_REG2_MONTH GENMASK(7, 0) -+#define RTC_REG_MAX 0xc -+ -+struct rtc_espi_sync { -+ struct rtc_device *rtc_dev; -+ struct device *dev; -+ void __iomem *espi_ram_base; -+ u32 interval_ms; -+ struct delayed_work sync_work; -+ struct workqueue_struct *wq; -+}; -+ -+static void sync_rtc_to_espi_work(struct work_struct *work) ++static int aspeed_ast2700_pcie_mmbi_init(struct platform_device *pdev) +{ -+ struct rtc_espi_sync *ctx = container_of(to_delayed_work(work), struct rtc_espi_sync, sync_work); -+ struct rtc_time tm; -+ u32 reg, sec, min, hour, day_of_week, day_of_month, month, year; -+ u32 sec_alarm, min_alarm, hour_alarm; -+ int ret; ++ struct aspeed_pcie_mmbi *mmbi = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 e2m_index, pid; ++ struct resource res; ++ int ret, i; ++ ++ /* Get register map*/ ++ mmbi->e2m = syscon_node_to_regmap(dev->of_node->parent); ++ if (IS_ERR(mmbi->e2m)) { ++ dev_err(dev, "failed to find e2m regmap\n"); ++ return PTR_ERR(mmbi->e2m); ++ } ++ if (of_address_to_resource(dev->of_node->parent, 0, &res)) { ++ dev_err(dev, "Failed to get e2m resource\n"); ++ return -EINVAL; ++ } ++ if (res.start == 0x14c1d000) ++ mmbi->id = 2; ++ else if (res.start == 0x12c22000) ++ mmbi->id = 1; ++ else ++ mmbi->id = 0; /* 0x12c21000 */ + -+ if (!ctx->espi_ram_base) { -+ dev_err(ctx->dev, "eSPI RAM base not mapped\n"); -+ return; ++ mmbi->device = syscon_regmap_lookup_by_phandle(dev->of_node->parent, "aspeed,device"); ++ if (IS_ERR(mmbi->device)) { ++ dev_err(dev, "failed to find device regmap\n"); ++ return PTR_ERR(mmbi->device); + } + -+ ret = rtc_read_time(ctx->rtc_dev, &tm); ++ ret = of_property_read_u32(dev->of_node, "index", &mmbi->e2m_index); + if (ret < 0) { -+ dev_err(ctx->dev, "Failed to read RTC time: %d\n", ret); -+ goto reschedule; ++ dev_err(dev, "cannot get mmbi index value\n"); ++ return ret; + } -+ dev_dbg(ctx->dev, "%s: tm data: secs=%d, mins=%d, hours=%d, mon=%d, year=%d\n", -+ __func__, tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_year); -+ dev_dbg(ctx->dev, "%s: tm data: wday(day of week)=%d, mday(day of month)=%d\n", -+ __func__, tm.tm_wday, tm.tm_mday); + -+ /* Write the eSPI RAM registers */ -+ reg = FIELD_PREP(RTC_REG0_SECONDS, tm.tm_sec) | -+ FIELD_PREP(RTC_REG0_MINUTES, tm.tm_min); -+ writel(reg, (ctx->espi_ram_base + RTC_REG0)); ++ ret = of_property_read_u32(dev->of_node, "pid", &mmbi->pid); ++ if (ret < 0) { ++ dev_err(dev, "cannot get mmbi pid value\n"); ++ return ret; ++ } + -+ reg = FIELD_PREP(RTC_REG1_HOURS, tm.tm_hour) | -+ FIELD_PREP(RTC_REG1_DAY_OF_MONTH, tm.tm_mday) | -+ FIELD_PREP(RTC_REG1_DAY_OF_WEEK, tm.tm_wday + 1); -+ writel(reg, ctx->espi_ram_base + RTC_REG1); ++ ret = of_property_read_u32(dev->of_node, "bar", &mmbi->scu_bar_offset); ++ if (ret < 0) { ++ dev_err(dev, "cannot get mmbi bar value\n"); ++ return ret; ++ } + -+ reg = FIELD_PREP(RTC_REG2_MONTH, tm.tm_mon + 1) | -+ FIELD_PREP(RTC_REG2_YEAR, tm.tm_year % 100); -+ writel(reg, ctx->espi_ram_base + RTC_REG2); ++ e2m_index = mmbi->e2m_index; ++ pid = mmbi->pid; ++ mmbi->e2m_h2b_int += mmbi->e2m_index; ++ if (mmbi->id < 2) { ++ /* PCIe device class, sub-class, protocol and reversion */ ++ regmap_write(mmbi->device, 0x18, 0x0C0C0027); ++ } else { ++ regmap_write(mmbi->device, 0x18, 0x0C0C0027); ++ regmap_write(mmbi->device, 0x78, ASPEED_SCU_INT_EN | ASPEED_SCU_DECODE_DEV); ++ } + -+ /* Read back the values to verify */ -+ reg = readl(ctx->espi_ram_base + RTC_REG0); -+ sec = FIELD_GET(RTC_REG0_SECONDS, reg); -+ sec_alarm = FIELD_GET(RTC_REG0_SECONDS_ALARM, reg); -+ min = FIELD_GET(RTC_REG0_MINUTES, reg); -+ min_alarm = FIELD_GET(RTC_REG0_MINUTES_ALARM, reg); ++ /* MSI */ ++ regmap_update_bits(mmbi->device, 0x74, GENMASK(7, 4), BIT(7) | (5 << 4)); + -+ reg = readl(ctx->espi_ram_base + RTC_REG1); -+ hour = FIELD_GET(RTC_REG1_HOURS, reg); -+ hour_alarm = FIELD_GET(RTC_REG1_HOURS_ALARM, reg); -+ day_of_week = FIELD_GET(RTC_REG1_DAY_OF_WEEK, reg); -+ day_of_month = FIELD_GET(RTC_REG1_DAY_OF_MONTH, reg); ++ regmap_update_bits(mmbi->device, 0x70, BIT(25) | BIT(17) | BIT(9) | BIT(1), ++ BIT(25) | BIT(17) | BIT(9) | BIT(1)); + -+ reg = readl(ctx->espi_ram_base + RTC_REG2); -+ month = FIELD_GET(RTC_REG2_MONTH, reg); -+ year = FIELD_GET(RTC_REG2_YEAR, reg); ++ /* Calculate the BAR Size */ ++ for (i = 1; i < 16; i++) { ++ /* bar size check for 4k align */ ++ if ((mmbi->mem_size / 4096) == (1 << (i - 1))) ++ break; ++ } ++ if (i == 16) { ++ i = 0; ++ dev_warn(dev, "Bar size not align for 4K : %dK\n", (u32)mmbi->mem_size / 1024); ++ } ++ regmap_write(mmbi->device, mmbi->scu_bar_offset, (mmbi->mem_phy >> 4) | i); ++ regmap_write(mmbi->e2m, ASPEED_E2M_ADRMAP00 + (4 * pid), (mmbi->mem_phy >> 4) | i); + -+ dev_dbg(ctx->dev, "%s: eSPI RAM data: secs=%d, mins=%d, hours=%d, ", -+ __func__, sec, min, hour); -+ dev_dbg(ctx->dev, "day_of_week=%d, day_of_month=%d, month=%d, year=%d\n", -+ day_of_week, day_of_month, month, year); -+ dev_dbg(ctx->dev, "%s: eSPI RAM data: secs_alarm=%d, mins_alarm=%d, hours_alarm=%d\n", -+ __func__, sec_alarm, min_alarm, hour_alarm); ++ ret = aspeed_pcie_mmbi_init(mmbi); ++ if (ret < 0) { ++ dev_err(dev, "Initialize MMBI device failed.\n"); ++ return ret; ++ } + -+reschedule: -+ queue_delayed_work(ctx->wq, &ctx->sync_work, msecs_to_jiffies(ctx->interval_ms)); ++ return 0; +} + -+static int rtc_espi_sync_probe(struct platform_device *pdev) ++struct aspeed_platform ast2700_platform = { ++ .mmbi_init = aspeed_ast2700_pcie_mmbi_init, ++}; ++ ++static const struct of_device_id aspeed_pcie_mmbi_of_matches[] = { ++ { .compatible = "aspeed,ast2700-pcie-mmbi", .data = &ast2700_platform }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aspeed_pcie_mmbi_of_matches); ++ ++static int aspeed_pcie_mmbi_probe(struct platform_device *pdev) +{ ++ struct aspeed_pcie_mmbi *mmbi; ++ struct mmbi_ins_desc *mmbi_desc; + struct device *dev = &pdev->dev; -+ struct rtc_espi_sync *ctx; -+ struct device_node *np = dev->of_node; -+ struct rtc_device *rtc; -+ struct resource *res; -+ u32 interval = SYNC_INTERVAL_MS_DEFAULT; ++ struct resource res; ++ struct device_node *np; ++ const void *md; ++ int i, ret = 0; + -+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) ++ md = of_device_get_match_data(dev); ++ if (!md) ++ return -ENODEV; ++ ++ mmbi = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_pcie_mmbi), GFP_KERNEL); ++ if (!mmbi) + return -ENOMEM; ++ dev_set_drvdata(dev, mmbi); + -+ /* Ensure the device tree node is valid */ -+ rtc = rtc_class_open("rtc0"); -+ if (!rtc) { -+ dev_info(dev, "RTC not ready, deferring probe\n"); -+ return -EPROBE_DEFER; -+ } ++ mmbi->dev = dev; ++ mmbi->platform = md; + -+ /* Check if the RTC device supports the read_time operation */ -+ if (!rtc->ops || !rtc->ops->read_time) { -+ dev_err(dev, "RTC device does not support read_time operation\n"); -+ rtc_class_close(rtc); -+ return -ENODEV; ++ /* Get MMBI memory size */ ++ np = of_parse_phandle(dev->of_node, "memory-region", 0); ++ if (!np || of_address_to_resource(np, 0, &res)) { ++ dev_err(dev, "Failed to find memory-region.\n"); ++ ret = -ENOMEM; ++ goto out_region; + } + -+ ctx->rtc_dev = rtc; -+ ctx->dev = dev; ++ of_node_put(np); + -+ /* Get eSPI RAM handle and map */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ ctx->espi_ram_base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(ctx->espi_ram_base)) -+ return PTR_ERR(ctx->espi_ram_base); ++ mmbi->mem_phy = res.start; ++ mmbi->mem_size = resource_size(&res); ++ mmbi->mem_virt = ioremap(mmbi->mem_phy, mmbi->mem_size); ++ if (!mmbi->mem_virt) { ++ dev_err(dev, "cannot map mmbi memory region\n"); ++ ret = -ENOMEM; ++ goto out_region; ++ } + -+ if (!ctx->espi_ram_base) -+ memset(ctx->espi_ram_base, 0, RTC_REG_MAX); ++ mmbi_desc = &mmbi->mmbi_desc; ++ memset(mmbi_desc, 0, sizeof(struct mmbi_ins_desc)); + -+ /* Optional: polling interval */ -+ of_property_read_u32(np, "interval-ms", &interval); -+ ctx->interval_ms = interval; ++ ret = of_property_read_u32(dev->of_node, "noi", &mmbi->num_of_channels); ++ if (ret || mmbi->num_of_channels == 0 || ++ mmbi->num_of_channels > MMBI_MAX_CHANNELS) { ++ dev_err(dev, "ret %d, MMBI NOI %d\n", ret, mmbi->num_of_channels); ++ goto out_unmap; ++ } ++ mmbi_desc->num_of_channels = mmbi->num_of_channels; + -+ ctx->wq = alloc_workqueue("rtc_espi_sync_wq", WQ_UNBOUND, 0); -+ if (!ctx->wq) -+ return -ENOMEM; ++ ret = aspeed_pcie_mmbi_parse_app_interface(dev, mmbi_desc); ++ if (ret) ++ goto out_unmap; + -+ INIT_DELAYED_WORK(&ctx->sync_work, sync_rtc_to_espi_work); -+ queue_delayed_work(ctx->wq, &ctx->sync_work, 0); ++ /* B2H Interrupt */ ++ mmbi->host_int_en = true; ++ ret = of_property_read_u32(dev->of_node, "msi", &mmbi->msi_index); ++ if (ret) { ++ dev_err(dev, "cannot get valid MMBI B2H interrupt location\n"); ++ mmbi->host_int_en = false; ++ } + -+ dev_info(dev, "RTC-eSPI RAM sync initialized, every %u ms\n", ctx->interval_ms); ++ ret = mmbi->platform->mmbi_init(pdev); ++ if (ret) { ++ dev_err(dev, "Initialize pcie mmbi failed\n"); ++ goto out_unmap; ++ } ++ ++ for (i = 0; i < mmbi_desc->num_of_channels; i++) ++ dev_info(dev, "channel %d application interface: %s\n", ++ i, aspeed_pcie_mmbi_app_interface_name(mmbi_desc->chan_desc[i].app_interface)); ++ dev_info(dev, "ASPEED PCIe MMBI Dev %d: driver successfully loaded.\n", mmbi->id); + -+ platform_set_drvdata(pdev, ctx); + return 0; ++out_unmap: ++ iounmap(mmbi->mem_virt); ++out_region: ++ devm_kfree(dev, mmbi); ++ dev_warn(dev, "aspeed pcie mmbi: driver init failed (ret=%d)!\n", ret); ++ return ret; +} + -+static void rtc_espi_sync_remove(struct platform_device *pdev) ++static void aspeed_pcie_mmbi_remove(struct platform_device *pdev) +{ -+ struct rtc_espi_sync *ctx = platform_get_drvdata(pdev); -+ -+ cancel_delayed_work_sync(&ctx->sync_work); -+ destroy_workqueue(ctx->wq); ++ struct aspeed_pcie_mmbi *mmbi = platform_get_drvdata(pdev); + -+ if (ctx->rtc_dev) -+ rtc_class_close(ctx->rtc_dev); ++ mmbi_instance_remove(&mmbi->mmbi_desc); ++ iounmap(mmbi->mem_virt); ++ devm_kfree(&pdev->dev, mmbi); +} + -+static const struct of_device_id rtc_espi_sync_of_match[] = { -+ { .compatible = "aspeed,ast2700-rtc-over-espi" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, rtc_espi_sync_of_match); -+ -+static struct platform_driver rtc_espi_sync_driver = { -+ .driver = { -+ .name = "ast2700-rtc-over-espi", -+ .of_match_table = rtc_espi_sync_of_match, ++static struct platform_driver aspeed_pcie_mmbi_driver = { ++ .probe = aspeed_pcie_mmbi_probe, ++ .remove = aspeed_pcie_mmbi_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_pcie_mmbi_of_matches, + }, -+ .probe = rtc_espi_sync_probe, -+ .remove = rtc_espi_sync_remove, +}; -+module_platform_driver(rtc_espi_sync_driver); + ++module_platform_driver(aspeed_pcie_mmbi_driver); ++ ++MODULE_AUTHOR("Jacky Chou "); ++MODULE_DESCRIPTION("ASPEED PCI-E MMBI Driver"); +MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Kevin Chen "); -+MODULE_DESCRIPTION("RTC to eSPI RAM sync driver"); +diff --git a/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.h b/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.h +--- a/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/soc/aspeed/mmbi/aspeed-pcie-mmbi.h 2026-09-09 15:51:44.722238011 +0000 +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright 2024 Aspeed Technology Inc. ++ */ ++#ifndef __ASPEED_PCIE_MMBI_H__ ++#define __ASPEED_PCIE_MMBI_H__ ++ ++struct aspeed_pcie_mmbi; ++ ++struct aspeed_mmbi_channel { ++ struct aspeed_pcie_mmbi *mmbi; ++ struct device *dev; ++ ++ bool bmc_int_en; ++ u8 bmc_int_value; ++ u32 bmc_int_location; ++ u8 __iomem *bmc_int_vmem; ++ ++ bool host_int_en; ++ u8 host_int_location; ++ u8 host_int_value; ++}; ++ ++#endif diff --git a/drivers/soc/aspeed/rvas/Kconfig b/drivers/soc/aspeed/rvas/Kconfig --- a/drivers/soc/aspeed/rvas/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/Kconfig 2025-12-23 10:16:21.127032619 +0000 ++++ b/drivers/soc/aspeed/rvas/Kconfig 2026-09-09 15:51:44.722238011 +0000 @@ -0,0 +1,9 @@ +menu "ASPEED RVAS drivers" + @@ -75200,14 +77391,14 @@ diff --git a/drivers/soc/aspeed/rvas/Kconfig b/drivers/soc/aspeed/rvas/Kconfig +endmenu diff --git a/drivers/soc/aspeed/rvas/Makefile b/drivers/soc/aspeed/rvas/Makefile --- a/drivers/soc/aspeed/rvas/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/Makefile 2025-12-23 10:16:21.127032619 +0000 ++++ b/drivers/soc/aspeed/rvas/Makefile 2026-09-09 15:51:44.722238011 +0000 @@ -0,0 +1,3 @@ +obj-$(CONFIG_ASPEED_RVAS) += rvas.o +rvas-y := video_main.o hardware_engines.o video_engine.o + diff --git a/drivers/soc/aspeed/rvas/hardware_engines.c b/drivers/soc/aspeed/rvas/hardware_engines.c --- a/drivers/soc/aspeed/rvas/hardware_engines.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/hardware_engines.c 2025-12-23 10:16:21.127032619 +0000 ++++ b/drivers/soc/aspeed/rvas/hardware_engines.c 2026-09-09 15:51:44.722238011 +0000 @@ -0,0 +1,2201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -77412,8 +79603,8 @@ diff --git a/drivers/soc/aspeed/rvas/hardware_engines.c b/drivers/soc/aspeed/rva + diff --git a/drivers/soc/aspeed/rvas/hardware_engines.h b/drivers/soc/aspeed/rvas/hardware_engines.h --- a/drivers/soc/aspeed/rvas/hardware_engines.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/hardware_engines.h 2025-12-23 10:16:21.127032619 +0000 -@@ -0,0 +1,550 @@ ++++ b/drivers/soc/aspeed/rvas/hardware_engines.h 2026-09-09 15:51:44.722238011 +0000 +@@ -0,0 +1,554 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file is part of the ASPEED Linux Device Driver for ASPEED Baseboard Management Controller. @@ -77505,7 +79696,11 @@ diff --git a/drivers/soc/aspeed/rvas/hardware_engines.h b/drivers/soc/aspeed/rva +#define SCU_RVAS_STOP_CLOCK_BIT BIT(25) +// +//MCR -edac -+#define MCR_CONF 0x04 /* configuration register */ ++#define MCR_CONF 0x04 /* configuration register */ ++ ++#define MCR_CONF_AST27XX 0x10 /* configuration register */ ++#define MCR_GRAPHIC_MEM_CONF_AST27XX 0x100 /* graphic memory configuration register */ ++#define MCR_GRAPHIC_MEM_BASE_AST27XX 0x10C /* graphic memory base: [25:17]vga1 in 16MB; [9:1]vga0 in 16MB */ + +//DP +#define DPTX_Configuration_Register (0x100) @@ -77757,7 +79952,7 @@ diff --git a/drivers/soc/aspeed/rvas/hardware_engines.h b/drivers/soc/aspeed/rva + +struct VGAMemInfo { + u32 dwVGASize; -+ u32 dwDRAMSize; ++ u64 qwDRAMSize; + phys_addr_t qwFBPhysStart; +}; + @@ -77827,7 +80022,7 @@ diff --git a/drivers/soc/aspeed/rvas/hardware_engines.h b/drivers/soc/aspeed/rva + +struct aspeed_rvas_config { + u8 version; -+ const u32 *dram_table; ++ const u64 *dram_table; +}; + +struct AstRVAS { @@ -77966,7 +80161,7 @@ diff --git a/drivers/soc/aspeed/rvas/hardware_engines.h b/drivers/soc/aspeed/rva +#endif // __HARDWAREENGINES_H__ diff --git a/drivers/soc/aspeed/rvas/video.h b/drivers/soc/aspeed/rvas/video.h --- a/drivers/soc/aspeed/rvas/video.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/video.h 2025-12-23 10:16:21.127032619 +0000 ++++ b/drivers/soc/aspeed/rvas/video.h 2026-09-09 15:51:44.722238011 +0000 @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/****************************************************************************** @@ -78011,8 +80206,8 @@ diff --git a/drivers/soc/aspeed/rvas/video.h b/drivers/soc/aspeed/rvas/video.h +#endif // __RVAS_VIDEO_H__ diff --git a/drivers/soc/aspeed/rvas/video_debug.h b/drivers/soc/aspeed/rvas/video_debug.h --- a/drivers/soc/aspeed/rvas/video_debug.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/video_debug.h 2025-12-23 10:16:21.127032619 +0000 -@@ -0,0 +1,35 @@ ++++ b/drivers/soc/aspeed/rvas/video_debug.h 2026-09-09 15:51:44.722238011 +0000 +@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019-2021 ASPEED Technology Inc. @@ -78030,27 +80225,30 @@ diff --git a/drivers/soc/aspeed/rvas/video_debug.h b/drivers/soc/aspeed/rvas/vid +//#define HARDWARE_ENGINE_DEBUG + +#ifdef RVAS_VIDEO_DEBUG -+#define VIDEO_DBG(fmt, args...) ({ dev_printk(KERNEL_INFO, pAstRVAS->pdev, "%s() " fmt, __func__, ## args); }) ++#define VIDEO_DBG(fmt, args...) \ ++dev_info(pAstRVAS->pdev, "%s() " fmt, __func__, ##args) +#else -+#define VIDEO_DBG(fmt, args...) do { (void)(fmt); (void)(args); } while (0) ++#define VIDEO_DBG(...) +#endif // RVAS_VIDEO_DEBUG + +#ifdef VIDEO_ENGINE_DEBUG -+#define VIDEO_ENG_DBG(fmt, args...) ({ dev_printk(KERNEL_INFO, pAstRVAS->pdev, "%s() " fmt, __func__, ## args); }) ++#define VIDEO_ENG_DBG(fmt, args...) \ ++dev_info(pAstRVAS->pdev, "%s() " fmt, __func__, ##args) +#else -+#define VIDEO_ENG_DBG(fmt, args...) do { (void)(fmt); (void)(args); } while (0) ++#define VIDEO_ENG_DBG(...) +#endif // RVAS_VIDEO_DEBUG + +#ifdef HARDWARE_ENGINE_DEBUG -+#define HW_ENG_DBG(fmt, args...) ({ dev_printk(KERNEL_INFO, pAstRVAS->pdev, "%s() " fmt, __func__, ## args); }) ++#define HW_ENG_DBG(fmt, args...) \ ++pr_info("%s() " fmt, __func__, ##args) +#else -+#define HW_ENG_DBG(fmt, args...) do { (void)(fmt); (void)(args); } while (0) ++#define HW_ENG_DBG(...) +#endif // RVAS_VIDEO_DEBUG + +#endif // AST_VIDEO_DEBUG_H_ diff --git a/drivers/soc/aspeed/rvas/video_engine.c b/drivers/soc/aspeed/rvas/video_engine.c --- a/drivers/soc/aspeed/rvas/video_engine.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/video_engine.c 2025-12-23 10:16:21.127032619 +0000 ++++ b/drivers/soc/aspeed/rvas/video_engine.c 2026-09-09 15:51:44.723237996 +0000 @@ -0,0 +1,1338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -78666,7 +80864,7 @@ diff --git a/drivers/soc/aspeed/rvas/video_engine.c b/drivers/soc/aspeed/rvas/vi +{ + u32 vga_mem_size, mem_size; + -+ mem_size = pAstRVAS->FBInfo.dwDRAMSize; ++ mem_size = pAstRVAS->FBInfo.qwDRAMSize; + vga_mem_size = pAstRVAS->FBInfo.dwVGASize; + VIDEO_ENG_DBG("VGA Info : MEM Size %dMB, VGA Mem Size %dMB\n", mem_size / 1024 / 1024, vga_mem_size / 1024 / 1024); + return (mem_size - vga_mem_size); @@ -79392,7 +81590,7 @@ diff --git a/drivers/soc/aspeed/rvas/video_engine.c b/drivers/soc/aspeed/rvas/vi +} diff --git a/drivers/soc/aspeed/rvas/video_engine.h b/drivers/soc/aspeed/rvas/video_engine.h --- a/drivers/soc/aspeed/rvas/video_engine.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/video_engine.h 2025-12-23 10:16:21.127032619 +0000 ++++ b/drivers/soc/aspeed/rvas/video_engine.h 2026-09-09 15:51:44.723237996 +0000 @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* @@ -79666,7 +81864,7 @@ diff --git a/drivers/soc/aspeed/rvas/video_engine.h b/drivers/soc/aspeed/rvas/vi +#endif // __VIDEO_ENGINE_H__ diff --git a/drivers/soc/aspeed/rvas/video_ioctl.h b/drivers/soc/aspeed/rvas/video_ioctl.h --- a/drivers/soc/aspeed/rvas/video_ioctl.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/video_ioctl.h 2025-12-23 10:16:21.128032602 +0000 ++++ b/drivers/soc/aspeed/rvas/video_ioctl.h 2026-09-09 15:51:44.723237996 +0000 @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* @@ -79945,8 +82143,8 @@ diff --git a/drivers/soc/aspeed/rvas/video_ioctl.h b/drivers/soc/aspeed/rvas/vid +#endif // _VIDEO_IOCTL_H diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/video_main.c --- a/drivers/soc/aspeed/rvas/video_main.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/rvas/video_main.c 2025-12-23 10:16:21.128032602 +0000 -@@ -0,0 +1,1848 @@ ++++ b/drivers/soc/aspeed/rvas/video_main.c 2026-09-09 15:51:44.723237996 +0000 +@@ -0,0 +1,1866 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * File Name : video_main.c @@ -80209,13 +82407,13 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide + pAstRVAS->FBInfo.qwFBPhysStart = (pAstRVAS->config->version == 7) + ? DDR_BASE_27 + : DDR_BASE; -+ pAstRVAS->FBInfo.qwFBPhysStart += pAstRVAS->FBInfo.dwDRAMSize - pAstRVAS->FBInfo.dwVGASize + dw_offset; ++ pAstRVAS->FBInfo.qwFBPhysStart += pAstRVAS->FBInfo.qwDRAMSize - pAstRVAS->FBInfo.dwVGASize + dw_offset; + if (pAstRVAS->rvas_index == 1) + pAstRVAS->FBInfo.qwFBPhysStart -= pAstRVAS->FBInfo.dwVGASize; + -+ HW_ENG_DBG("Frame buffer start address: %#x, dram size: %#x, vga size: %#x\n", ++ HW_ENG_DBG("Frame buffer start address: %#llx, dram size: %#x, vga size: %#x\n", + pAstRVAS->FBInfo.qwFBPhysStart, -+ pAstRVAS->FBInfo.dwDRAMSize, ++ pAstRVAS->FBInfo.qwDRAMSize, + pAstRVAS->FBInfo.dwVGASize); + + return pAstRVAS->FBInfo.qwFBPhysStart; @@ -81100,9 +83298,12 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide +static void reset_rvas_engine(struct AstRVAS *pAstRVAS) +{ + disable_rvas_engines(pAstRVAS); ++ mdelay(200); + if (pAstRVAS->config->version == 7) + reset_control_deassert(pAstRVAS->rvas_reset); ++ mdelay(200); + enable_rvas_engines(pAstRVAS); ++ + rvas_init(pAstRVAS); +} + @@ -81594,22 +83795,22 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide + if (!pAstRVAS->dp_base) + dev_err(&pdev->dev, "failed to iomem of display port\n"); + } -+ if (pAstRVAS->config->version == 7) { -+ pAstRVAS->FBInfo.dwDRAMSize = 0x40000000; // 1GB -+ // VGA size is fixed with 32MB -+ pAstRVAS->FBInfo.dwVGASize = 0x2000000; -+ } else { ++ ++ if (pAstRVAS->config->version == 7) ++ edac_node = of_find_compatible_node(NULL, NULL, "aspeed,ast2700-sdram-edac"); ++ else + edac_node = of_find_compatible_node(NULL, NULL, "aspeed,ast2600-sdram-edac"); -+ if (!edac_node) { -+ dev_err(&pdev->dev, "cannot find edac node\n"); -+ } else { -+ mcr_base = of_iomap(edac_node, 0); -+ if (!mcr_base) -+ dev_err(&pdev->dev, "failed to iomem of MCR\n"); -+ } + -+ set_FBInfo_size(pAstRVAS, mcr_base); ++ if (!edac_node) { ++ dev_err(&pdev->dev, "cannot find edac node\n"); ++ } else { ++ mcr_base = of_iomap(edac_node, 0); ++ if (!mcr_base) ++ dev_err(&pdev->dev, "failed to iomem of MCR\n"); + } ++ ++ set_FBInfo_size(pAstRVAS, mcr_base); ++ + //scu + if (pAstRVAS->config->version == 7) { + sdram_scu = syscon_regmap_lookup_by_compatible("aspeed,ast2700-scu0"); @@ -81705,7 +83906,7 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide + enable_video_interrupt(pAstRVAS); +} + -+static int video_drv_remove(struct platform_device *pdev) ++static void video_drv_remove(struct platform_device *pdev) +{ + struct AstRVAS *pAstRVAS = NULL; + @@ -81726,31 +83927,39 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide + + free_video_engine_memory(pAstRVAS); + pr_info("RVAS: driver successfully unloaded.\n"); -+ return 0; +} + -+static const u32 ast2400_dram_table[] = { ++static const u64 ast2400_dram_table[] = { + 0x04000000, //64MB + 0x08000000, //128MB + 0x10000000, //256MB + 0x20000000, //512MB +}; + -+static const u32 ast2500_dram_table[] = { ++static const u64 ast2500_dram_table[] = { + 0x08000000, //128MB + 0x10000000, //256MB + 0x20000000, //512MB + 0x40000000, //1024MB +}; + -+static const u32 ast2600_dram_table[] = { ++static const u64 ast2600_dram_table[] = { ++ 0x10000000, //256MB ++ 0x20000000, //512MB ++ 0x40000000, //1024MB ++ 0x80000000, //2048MB ++}; ++ ++static const u64 ast2700_dram_table[] = { + 0x10000000, //256MB + 0x20000000, //512MB + 0x40000000, //1024MB + 0x80000000, //2048MB ++ 0x100000000, //4GB ++ 0x200000000, //8GB +}; + -+static const u32 aspeed_vga_table[] = { ++static const u64 aspeed_vga_table[] = { + 0x800000, //8MB + 0x1000000, //16MB + 0x2000000, //32MB @@ -81764,16 +83973,23 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide + +static const struct aspeed_rvas_config ast2700_config = { + .version = 7, -+ .dram_table = ast2600_dram_table, ++ .dram_table = ast2700_dram_table, +}; + +static void set_FBInfo_size(struct AstRVAS *pAstRVAS, void __iomem *mcr_base) +{ -+ u32 reg_mcr004 = readl(mcr_base + MCR_CONF); ++ if (pAstRVAS->config->version == 7) { ++ u32 reg_mcr010 = readl(mcr_base + MCR_CONF_AST27XX); ++ u32 reg_mcr100 = readl(mcr_base + MCR_GRAPHIC_MEM_CONF_AST27XX); + -+ pAstRVAS->FBInfo.dwDRAMSize = pAstRVAS->config->dram_table[reg_mcr004 & 0x3]; ++ pAstRVAS->FBInfo.qwDRAMSize = pAstRVAS->config->dram_table[((reg_mcr010 & 0x1c) >> 2)]; ++ pAstRVAS->FBInfo.dwVGASize = (reg_mcr100 & 0x1) ? 0x4000000 : 0x2000000; ++ } else { ++ u32 reg_mcr004 = readl(mcr_base + MCR_CONF); + -+ pAstRVAS->FBInfo.dwVGASize = aspeed_vga_table[((reg_mcr004 & 0xC) >> 2)]; ++ pAstRVAS->FBInfo.qwDRAMSize = pAstRVAS->config->dram_table[reg_mcr004 & 0x3]; ++ pAstRVAS->FBInfo.dwVGASize = aspeed_vga_table[((reg_mcr004 & 0xC) >> 2)]; ++ } +} + +static const struct of_device_id ast_rvas_match[] = { @@ -81795,40 +84011,9 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide +MODULE_AUTHOR("ASPEED Technology"); +MODULE_DESCRIPTION("RVAS video driver module for AST2600"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig ---- a/drivers/spi/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/spi/Kconfig 2025-12-23 10:16:09.442228501 +0000 -@@ -129,6 +129,16 @@ - controller (SPI) for the host firmware. The implementation - only supports SPI NOR. - -+config SPI_ASPEED_TXRX -+ tristate "Aspeed SPI controllers" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ depends on OF -+ help -+ This enables support for SPI controller driver in the Aspeed -+ AST2600, AST2500 and AST2400 SoCs when attached -+ to SPI device chips with half-duplex mode. On AST2700, -+ full-duplex mode can be enabled. -+ - config SPI_ATMEL - tristate "Atmel SPI Controller" - depends on ARCH_AT91 || COMPILE_TEST -diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile ---- a/drivers/spi/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/spi/Makefile 2025-12-23 10:16:13.600158773 +0000 -@@ -22,6 +22,7 @@ - obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o - obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o - obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o -+obj-$(CONFIG_SPI_ASPEED_TXRX) += spi-aspeed-txrx.o - obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o - obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o - obj-$(CONFIG_SPI_AT91_USART) += spi-at91-usart.o diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c ---- a/drivers/spi/spi-aspeed-smc.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/spi/spi-aspeed-smc.c 2025-12-23 10:16:21.071033558 +0000 +--- a/drivers/spi/spi-aspeed-smc.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/spi/spi-aspeed-smc.c 2026-09-09 15:51:44.654239039 +0000 @@ -7,10 +7,16 @@ */ @@ -83607,7 +85792,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c + goto end; + } + - ret = devm_spi_register_controller(dev, ctlr); + ret = spi_register_controller(ctlr); - if (ret) + if (ret) { dev_err(&pdev->dev, "spi_register_controller failed\n"); @@ -83618,9 +85803,9 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c return ret; } -@@ -783,6 +1753,13 @@ - { - struct aspeed_spi *aspi = platform_get_drvdata(pdev); +@@ -786,6 +1756,13 @@ + + spi_unregister_controller(ctlr); + if (aspi->op_buf) { + dma_free_coherent(aspi->dev, @@ -83632,7 +85817,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c aspeed_spi_enable(aspi, false); } -@@ -795,19 +1772,20 @@ +@@ -798,19 +1775,20 @@ * The address range is encoded with absolute addresses in the overall * mapping window. */ @@ -83657,7 +85842,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c } /* -@@ -817,18 +1795,18 @@ +@@ -820,18 +1798,18 @@ #define AST2600_SEG_ADDR_MASK 0x0ff00000 @@ -83680,7 +85865,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c /* segment is disabled */ if (!end_offset) -@@ -838,28 +1816,193 @@ +@@ -841,28 +1819,193 @@ } static u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi, @@ -83879,7 +86064,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c memcpy_fromio(test_buf, chip->ahb_base, CALIBRATE_BUF_SIZE); if (memcmp(test_buf, golden_buf, CALIBRATE_BUF_SIZE) != 0) { #if defined(VERBOSE_DEBUG) -@@ -872,7 +2015,10 @@ +@@ -875,7 +2018,10 @@ return true; } @@ -83891,7 +86076,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c /* * The timing register is shared by all devices. Only update for CE0. -@@ -902,7 +2048,7 @@ +@@ -905,7 +2051,7 @@ pass = aspeed_spi_check_reads(chip, golden_buf, test_buf); dev_dbg(aspi->dev, " * [%08x] %d HCLK delay, %dns DI delay : %s", @@ -83900,7 +86085,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c pass ? "PASS" : "FAIL"); if (pass) { pass_count++; -@@ -948,17 +2094,6 @@ +@@ -951,17 +2097,6 @@ return cnt >= 64; } @@ -83918,7 +86103,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip) { struct aspeed_spi *aspi = chip->aspi; -@@ -969,10 +2104,17 @@ +@@ -972,10 +2107,17 @@ u8 *golden_buf = NULL; u8 *test_buf = NULL; int i, rc, best_div = -1; @@ -83936,7 +86121,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c /* * use the related low frequency to get check calibration data * and get golden data. -@@ -988,7 +2130,7 @@ +@@ -991,7 +2133,7 @@ memcpy_fromio(golden_buf, chip->ahb_base, CALIBRATE_BUF_SIZE); if (!aspeed_spi_check_calib_data(golden_buf, CALIBRATE_BUF_SIZE)) { @@ -83945,7 +86130,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c goto no_calib; } -@@ -998,42 +2140,81 @@ +@@ -1001,42 +2143,81 @@ #endif /* Now we iterate the HCLK dividers until we find our breaking point */ @@ -84039,7 +86224,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c #define TIMING_REG_AST2600(chip) \ ((chip)->aspi->regs + (chip)->aspi->data->timing + \ (chip)->cs * 4) -@@ -1041,60 +2222,136 @@ +@@ -1044,60 +2225,136 @@ static int aspeed_spi_ast2600_calibrate(struct aspeed_spi_chip *chip, u32 hdiv, const u8 *golden_buf, u8 *test_buf) { @@ -84206,7 +86391,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c .max_cs = 5, .hastype = true, .we0 = 16, -@@ -1102,13 +2359,17 @@ +@@ -1105,13 +2362,17 @@ .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xfffff0ff, .hdiv_max = 1, @@ -84224,7 +86409,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c .max_cs = 1, .hastype = false, .we0 = 0, -@@ -1116,11 +2377,13 @@ +@@ -1119,11 +2380,13 @@ .timing = 0x14, .hclk_mask = 0xfffff0ff, .hdiv_max = 1, @@ -84238,7 +86423,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c .max_cs = 3, .hastype = true, .we0 = 16, -@@ -1128,13 +2391,17 @@ +@@ -1131,13 +2394,17 @@ .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xffffd0ff, .hdiv_max = 1, @@ -84256,7 +86441,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c .max_cs = 2, .hastype = false, .we0 = 16, -@@ -1142,13 +2409,17 @@ +@@ -1145,13 +2412,17 @@ .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xffffd0ff, .hdiv_max = 1, @@ -84274,7 +86459,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c .max_cs = 3, .hastype = false, .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD, -@@ -1157,13 +2428,17 @@ +@@ -1160,13 +2431,17 @@ .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xf0fff0ff, .hdiv_max = 2, @@ -84292,7 +86477,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c .max_cs = 2, .hastype = false, .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD, -@@ -1172,10 +2447,53 @@ +@@ -1175,10 +2450,53 @@ .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xf0fff0ff, .hdiv_max = 2, @@ -84346,7 +86531,7 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c }; static const struct of_device_id aspeed_spi_matches[] = { -@@ -1185,6 +2503,8 @@ +@@ -1188,6 +2506,8 @@ { .compatible = "aspeed,ast2500-spi", .data = &ast2500_spi_data }, { .compatible = "aspeed,ast2600-fmc", .data = &ast2600_fmc_data }, { .compatible = "aspeed,ast2600-spi", .data = &ast2600_spi_data }, @@ -84357,8 +86542,8 @@ diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c MODULE_DEVICE_TABLE(of, aspeed_spi_matches); diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c --- a/drivers/spi/spi-aspeed-txrx.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/spi/spi-aspeed-txrx.c 2025-12-23 10:16:21.065033658 +0000 -@@ -0,0 +1,622 @@ ++++ b/drivers/spi/spi-aspeed-txrx.c 2026-09-09 15:51:44.647239144 +0000 +@@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) ASPEED Technology Inc. @@ -84411,8 +86596,9 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + u32 ahb_clk; + u32 ctrl_val[5]; + void __iomem *chip_ahb_base[5]; -+ u8 cs_change; ++ struct spi_device *cs_change_spi; + const struct aspeed_spi_info *info; ++ u32 saved_host_cmd_ctrl; +}; + +struct aspeed_spi_info { @@ -84699,6 +86885,11 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + writel(ctrl_val, ctrl_reg); +} + ++static void aspeed_spi_restore_host_cmd_ctrl(struct aspeed_spi_host *host) ++{ ++ writel(host->saved_host_cmd_ctrl, host->ctrl_reg + SPI_MISC_CTRL); ++} ++ +static void aspeed_spi_transfer_tx(struct aspeed_spi_host *host, const u8 *tx_buf, + u8 *rx_buf, void *dst, u32 len) +{ @@ -84712,6 +86903,18 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + } +} + ++/* ++ * aspeed_spi_transfer - transfer_one_message callback ++ * ++ * SPI_MISC_CTRL holds the host command configuration and must be cleared ++ * before entering user mode; it is saved here and restored only when CS ++ * is finally deasserted. ++ * ++ * cs_change on the last transfer keeps CS active across messages ++ * (cs_change_spi tracks the owning device). cs_change on any earlier ++ * transfer toggles CS in place. A stale CS held by another device is ++ * force-released before the new message begins. ++ */ +static int aspeed_spi_transfer(struct spi_controller *ctlr, + struct spi_message *msg) +{ @@ -84724,22 +86927,38 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + u8 *rx_buf; + u32 cs; + u32 j = 0; -+ u32 ctrl_val, normal_mode; ++ u32 ctrl_val; + void __iomem *ctrl_reg; ++ bool is_last; ++ bool keep_cs = false; ++ ++ /* Drop a CS held by another device before starting this message. */ ++ if (host->cs_change_spi && host->cs_change_spi != spi) { ++ dev_warn(dev, "CS was kept active for another SPI device, releasing it\n"); ++ ++ aspeed_spi_stop_user(host->cs_change_spi); ++ aspeed_spi_restore_host_cmd_ctrl(host); ++ ++ host->cs_change_spi = NULL; ++ } ++ ++ /* Backup host command mode information from MISC_CTRL register before activating CS */ ++ if (!host->cs_change_spi) { ++ host->saved_host_cmd_ctrl = readl(host->ctrl_reg + SPI_MISC_CTRL); + -+ if (host->cs_change == 0) ++ writel(0x0, host->ctrl_reg + SPI_MISC_CTRL); + aspeed_spi_start_user(spi); ++ } + + cs = spi_get_chipselect(spi, 0); + ctrl_reg = host->ctrl_reg + SPI_CE0_CTRL + cs * 4; + ctrl_val = readl(ctrl_reg); + -+ normal_mode = readl(host->ctrl_reg + SPI_MISC_CTRL); -+ writel(0x0, host->ctrl_reg + SPI_MISC_CTRL); -+ + dev_dbg(dev, "cs: %d\n", cs); + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { ++ is_last = list_is_last(&xfer->transfer_list, &msg->transfers); ++ + dev_dbg(dev, + "xfer[%d]: width %d, len %u, tx %p, rx %p\n", + j, @@ -84751,9 +86970,9 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + + if (tx_buf) { + ctrl_val &= ~SPI_IO_MASK; -+ if (spi->mode & SPI_TX_DUAL) ++ if (xfer->tx_nbits == SPI_NBITS_DUAL) + ctrl_val |= SPI_DUAL_IO_MODE; -+ else if (spi->mode & SPI_TX_QUAD) ++ else if (xfer->tx_nbits == SPI_NBITS_QUAD) + ctrl_val |= SPI_QUAD_IO_MODE; + writel(ctrl_val, ctrl_reg); + @@ -84769,9 +86988,9 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + + if (rx_buf && rx_buf != tx_buf) { + ctrl_val &= ~SPI_IO_MASK; -+ if (spi->mode & SPI_RX_DUAL) ++ if (xfer->rx_nbits == SPI_NBITS_DUAL) + ctrl_val |= SPI_DUAL_IO_MODE; -+ else if (spi->mode & SPI_RX_QUAD) ++ else if (xfer->rx_nbits == SPI_NBITS_QUAD) + ctrl_val |= SPI_QUAD_IO_MODE; + writel(ctrl_val, ctrl_reg); + @@ -84784,16 +87003,32 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + } + + msg->actual_length += xfer->len; -+ host->cs_change = xfer->cs_change; ++ ++ /* Non-final cs_change toggles CS; final cs_change keeps it active. */ ++ if (xfer->cs_change) { ++ if (is_last) { ++ keep_cs = true; ++ } else { ++ aspeed_spi_stop_user(spi); ++ /* CS deassert-to-reassert delay; uses xfer->cs_change_delay if set, else 10us */ ++ spi_transfer_cs_change_delay_exec(msg, xfer); ++ aspeed_spi_start_user(spi); ++ } ++ } ++ + j++; + } + -+ if (host->cs_change == 0) ++ if (!keep_cs) { + aspeed_spi_stop_user(spi); ++ aspeed_spi_restore_host_cmd_ctrl(host); + -+ msg->status = 0; ++ host->cs_change_spi = NULL; ++ } else { ++ host->cs_change_spi = spi; ++ } + -+ writel(normal_mode, host->ctrl_reg + SPI_MISC_CTRL); ++ msg->status = 0; + + spi_finalize_current_message(ctlr); + @@ -84980,11 +87215,10 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c +MODULE_AUTHOR("Ryan Chen"); +MODULE_AUTHOR("Chin-Ting Kuo"); +MODULE_LICENSE("GPL"); -+ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c --- a/drivers/tty/serial/8250/8250_aspeed.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/tty/serial/8250/8250_aspeed.c 2025-12-23 10:16:20.962035385 +0000 -@@ -0,0 +1,524 @@ ++++ b/drivers/tty/serial/8250/8250_aspeed.c 2026-09-09 15:51:44.527240958 +0000 +@@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. @@ -85001,6 +87235,7 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +#include +#include +#include ++#include +#include +#include +#include @@ -85027,7 +87262,6 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +#define VUART_GCRG 0x38 +#define VUART_GCRG_CHARACTER_TIMEOUT_TIME_CONTROL BIT(1) + -+#define DMA_TX_BUFSZ PAGE_SIZE +#define DMA_RX_BUFSZ (64 * 1024) + +struct uart_ops ast8250_pops; @@ -85042,14 +87276,14 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +struct ast8250_udma { + u32 ch; + -+ u32 tx_fifosz; -+ u32 rx_fifosz; ++ u32 tx_rbsz; ++ u32 rx_rbsz; + + dma_addr_t tx_addr; + dma_addr_t rx_addr; + -+ struct kfifo *tx_fifo; -+ struct kfifo *rx_fifo; ++ struct tty_port *tport; ++ struct circ_buf *rx_rb; + + bool tx_tmout_dis; + bool rx_tmout_dis; @@ -85058,6 +87292,7 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +struct ast8250_data { + int line; + ++ struct resource *res; + u8 __iomem *regs; + + bool is_vuart; @@ -85070,62 +87305,76 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + struct ast8250_udma dma; +}; + -+static void ast8250_dma_tx_complete(int tx_fifo_rptr, void *id) ++static void ast8250_dma_tx_complete(int tx_rb_rptr, void *id) +{ -+ unsigned long flags; -+ struct uart_port *port = (struct uart_port*)id; ++ unsigned long flags; ++ struct uart_port *port = id; + struct ast8250_data *data = port->private_data; -+ struct kfifo *tx_fifo = data->dma.tx_fifo; -+ unsigned int len; ++ unsigned int count, tail; + -+ spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + -+ len = kfifo_out(tx_fifo, NULL, tx_fifo_rptr); -+ port->icount.tx += len; ++ count = kfifo_out_linear(&data->dma.tport->xmit_fifo, &tail, data->dma.tx_rbsz); ++ count = CIRC_CNT(tx_rb_rptr, tail, data->dma.tx_rbsz); ++ if (!count) ++ count = data->dma.tx_rbsz; ++ kfifo_dma_out_finish(&data->dma.tport->xmit_fifo, count); ++ port->icount.tx += count; + -+ if (kfifo_len(tx_fifo) < WAKEUP_CHARS) ++ if (kfifo_len(&data->dma.tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + -+ spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); +} + -+static void ast8250_dma_rx_complete(int rx_fifo_wptr, void *id) ++static void ast8250_dma_rx_complete(int rx_rb_wptr, void *id) +{ + unsigned long flags; + struct uart_port *up = (struct uart_port*)id; + struct tty_port *tp = &up->state->port; + struct ast8250_data *data = up->private_data; + struct ast8250_udma *dma = &data->dma; -+ struct kfifo *rx_fifo = dma->rx_fifo; -+ u32 len = 0; -+ u8 buf[128]; ++ struct circ_buf *rx_rb = dma->rx_rb; ++ u32 rx_rbsz = dma->rx_rbsz; ++ u32 count = 0; ++ ++ uart_port_lock_irqsave(up, &flags); + -+ spin_lock_irqsave(&up->lock, flags); ++ rx_rb->head = rx_rb_wptr; + + dma_sync_single_for_cpu(up->dev, -+ dma->rx_addr, dma->rx_fifosz, DMA_FROM_DEVICE); ++ dma->rx_addr, dma->rx_rbsz, DMA_FROM_DEVICE); + -+ while (!kfifo_is_empty(rx_fifo)) { -+ len = kfifo_out(rx_fifo, buf, sizeof(buf)); -+ tty_insert_flip_string(tp, buf, len); -+ up->icount.rx += len; ++ while (CIRC_CNT(rx_rb->head, rx_rb->tail, rx_rbsz)) { ++ count = CIRC_CNT_TO_END(rx_rb->head, rx_rb->tail, rx_rbsz); ++ ++ tty_insert_flip_string(tp, rx_rb->buf + rx_rb->tail, count); ++ ++ rx_rb->tail += count; ++ rx_rb->tail %= rx_rbsz; ++ ++ up->icount.rx += count; + } + -+ tty_flip_buffer_push(tp); ++ if (count) { ++ aspeed_udma_set_rx_rptr(data->dma.ch, rx_rb->tail); ++ tty_flip_buffer_push(tp); ++ } + -+ spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); +} + +static void ast8250_dma_start_tx(struct uart_port *port) +{ + struct ast8250_data *data = port->private_data; + struct ast8250_udma *dma = &data->dma; -+ struct kfifo *tx_fifo = dma->tx_fifo; ++ typeof(&dma->tport->xmit_fifo) tmp = &dma->tport->xmit_fifo; ++ struct __kfifo *tx_rb = &tmp->kfifo; + + dma_sync_single_for_device(port->dev, -+ dma->tx_addr, dma->tx_fifosz, DMA_TO_DEVICE); ++ dma->tx_addr, dma->tx_rbsz, DMA_TO_DEVICE); + -+ aspeed_udma_set_tx_wptr(dma->ch, kfifo_len(tx_fifo)); ++ aspeed_udma_set_tx_wptr(dma->ch, tx_rb->in); +} + +static void ast8250_dma_pops_hook(struct uart_port *port) @@ -85219,49 +87468,53 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + if (data->use_dma) { + dma = &data->dma; + -+ dma->tx_fifosz = DMA_TX_BUFSZ; -+ dma->rx_fifosz = DMA_RX_BUFSZ; ++ dma->tx_rbsz = UART_XMIT_SIZE; ++ dma->rx_rbsz = DMA_RX_BUFSZ; + -+ if (kfifo_alloc(dma->tx_fifo, dma->tx_fifosz, GFP_KERNEL)) { -+ dev_err(port->dev, "failed to allocate TX DMA ring buffer\n"); ++ /* ++ * We take the xmit buffer passed from upper layers as ++ * the DMA TX buffer and allocate a new buffer for the ++ * RX use. ++ * ++ * To keep the TX/RX operation consistency, we use the ++ * streaming DMA interface instead of the coherent one ++ */ ++ dma->tport = &port->state->port; ++ dma->rx_rb->buf = kzalloc(data->dma.rx_rbsz, GFP_KERNEL); ++ if (IS_ERR_OR_NULL(dma->rx_rb->buf)) { ++ dev_err(port->dev, "failed to allcoate RX DMA buffer\n"); + rc = -ENOMEM; + goto out; + } + -+ if (kfifo_alloc(dma->rx_fifo, dma->rx_fifosz, GFP_KERNEL)) { -+ dev_err(port->dev, "failed to allocate RX DMA ring buffer\n"); -+ rc = -ENOMEM; -+ goto free_tx_fifo; -+ } -+ -+ dma->tx_addr = dma_map_single(port->dev, dma->tx_fifo->kfifo.data, -+ dma->tx_fifosz, DMA_TO_DEVICE); ++ dma->tx_addr = dma_map_single(port->dev, dma->tport->xmit_buf, ++ dma->tx_rbsz, DMA_TO_DEVICE); + if (dma_mapping_error(port->dev, dma->tx_addr)) { + dev_err(port->dev, "failed to map streaming TX DMA region\n"); + rc = -ENOMEM; -+ goto free_rx_fifo; ++ goto free_dma_n_out; + } + -+ dma->rx_addr = dma_map_single(port->dev, dma->rx_fifo->kfifo.data, -+ dma->rx_fifosz, DMA_FROM_DEVICE); ++ dma->rx_addr = dma_map_single(port->dev, dma->rx_rb->buf, ++ dma->rx_rbsz, DMA_FROM_DEVICE); + if (dma_mapping_error(port->dev, dma->rx_addr)) { + dev_err(port->dev, "failed to map streaming RX DMA region\n"); + rc = -ENOMEM; -+ goto free_rx_fifo; ++ goto free_dma_n_out; + } + + rc = aspeed_udma_request_tx_chan(dma->ch, dma->tx_addr, -+ dma->tx_fifo, dma->tx_fifosz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis); ++ dma->tx_rbsz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis); + if (rc) { + dev_err(port->dev, "failed to request DMA TX channel\n"); -+ goto free_rx_fifo; ++ goto free_dma_n_out; + } + + rc = aspeed_udma_request_rx_chan(dma->ch, dma->rx_addr, -+ dma->rx_fifo, dma->rx_fifosz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis); ++ dma->rx_rbsz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis); + if (rc) { + dev_err(port->dev, "failed to request DMA RX channel\n"); -+ goto free_rx_fifo; ++ goto free_dma_n_out; + } + + ast8250_dma_pops_hook(port); @@ -85273,12 +87526,8 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + memset(&port->icount, 0, sizeof(port->icount)); + return serial8250_do_startup(port); + -+free_rx_fifo: -+ kfifo_free(dma->rx_fifo); -+ -+free_tx_fifo: -+ kfifo_free(dma->tx_fifo); -+ ++free_dma_n_out: ++ kfree(dma->rx_rb->buf); +out: + return rc; +} @@ -85307,12 +87556,12 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + dev_err(port->dev, "failed to free DMA TX channel, rc=%d\n", rc); + + dma_unmap_single(port->dev, dma->tx_addr, -+ dma->tx_fifosz, DMA_TO_DEVICE); ++ dma->tx_rbsz, DMA_TO_DEVICE); + dma_unmap_single(port->dev, dma->rx_addr, -+ dma->rx_fifosz, DMA_FROM_DEVICE); ++ dma->rx_rbsz, DMA_FROM_DEVICE); + -+ kfree(dma->tx_fifo); -+ kfree(dma->rx_fifo); ++ if (dma->rx_rb->buf) ++ kfree(dma->rx_rb->buf); + } + + if (data->is_vuart) @@ -85335,46 +87584,19 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + return 0; +} + -+static int ast8250_probe(struct platform_device *pdev) ++static int ast8250_probe_of(struct platform_device *pdev, struct uart_port *p, ++ struct ast8250_data *data) +{ -+ int rc; -+ struct uart_8250_port uart = {}; -+ struct uart_port *port = &uart.port; + struct device *dev = &pdev->dev; -+ struct ast8250_data *data; -+ uint32_t plat = (unsigned long)of_device_get_match_data(dev); -+ -+ struct resource *res; -+ u32 irq; -+ -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; -+ } -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if (data == NULL) -+ return -ENOMEM; -+ -+ data->dma.rx_fifo = devm_kzalloc(dev, sizeof(data->dma.rx_fifo), GFP_KERNEL); -+ if (!data->dma.rx_fifo) -+ return -ENOMEM; -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ if (irq != -EPROBE_DEFER) -+ dev_err(dev, "failed to get IRQ number\n"); -+ return irq; -+ } ++ int rc; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { ++ data->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!data->res) { + dev_err(dev, "failed to get register base\n"); + return -ENODEV; + } + -+ data->regs = devm_ioremap(dev, res->start, resource_size(res)); ++ data->regs = devm_ioremap(dev, data->res->start, resource_size(data->res)); + if (IS_ERR(data->regs)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(data->regs); @@ -85386,18 +87608,12 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + return -ENODEV; + } + -+ rc = clk_prepare_enable(data->clk); -+ if (rc) { -+ dev_err(dev, "failed to enable clock\n"); -+ return rc; -+ } -+ + data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); -+ if (!IS_ERR(data->rst)) -+ reset_control_deassert(data->rst); + + data->is_vuart = of_property_read_bool(dev->of_node, "virtual"); + if (data->is_vuart) { ++ u32 plat = (unsigned long)of_device_get_match_data(dev); ++ + rc = of_property_read_u32(dev->of_node, "port", &data->vuart.port); + if (rc) { + dev_err(dev, "failed to get VUART port address\n"); @@ -85420,17 +87636,10 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + data->vuart.character_timeout_time_en = true; + else + data->vuart.character_timeout_time_en = false; -+ -+ ast8250_vuart_init(data); -+ ast8250_vuart_set_host_tx_discard(data, true); -+ ast8250_vuart_set_enable(data, true); + } + + data->use_dma = of_property_read_bool(dev->of_node, "dma-mode"); + if (data->use_dma) { -+ dev_warn(dev, "DMA mode not ready\n"); -+ data->use_dma = false; -+ /* + rc = of_property_read_u32(dev->of_node, "dma-channel", &data->dma.ch); + if (rc) { + dev_err(dev, "failed to get DMA channel\n"); @@ -85439,27 +87648,73 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + + data->dma.tx_tmout_dis = of_property_read_bool(dev->of_node, "dma-tx-timeout-disable"); + data->dma.rx_tmout_dis = of_property_read_bool(dev->of_node, "dma-rx-timeout-disable"); -+ */ ++ } ++ ++ return 0; ++} ++ ++static int ast8250_probe(struct platform_device *pdev) ++{ ++ int rc; ++ struct uart_8250_port uart = {}; ++ struct uart_port *port = &uart.port; ++ struct device *dev = &pdev->dev; ++ struct ast8250_data *data; ++ ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ dev_err(dev, "cannot set 64-bits DMA mask\n"); ++ return rc; ++ } ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->dma.rx_rb = devm_kzalloc(dev, sizeof(data->dma.rx_rb), GFP_KERNEL); ++ if (!data->dma.rx_rb) ++ return -ENOMEM; ++ ++ rc = ast8250_probe_of(pdev, port, data); ++ if (rc) ++ return rc; ++ ++ rc = clk_prepare_enable(data->clk); ++ if (rc) { ++ dev_err(dev, "failed to enable clock\n"); ++ return rc; ++ } ++ ++ if (!IS_ERR(data->rst)) ++ reset_control_deassert(data->rst); ++ ++ if (data->is_vuart) { ++ ast8250_vuart_init(data); ++ ast8250_vuart_set_host_tx_discard(data, true); ++ ast8250_vuart_set_enable(data, true); + } + + spin_lock_init(&port->lock); + port->dev = dev; -+ port->type = PORT_16550A; -+ port->irq = irq; -+ port->line = of_alias_get_id(dev->of_node, "serial"); -+ port->handle_irq = ast8250_handle_irq; -+ port->mapbase = res->start; -+ port->mapsize = resource_size(res); ++ port->mapbase = data->res->start; ++ port->mapsize = resource_size(data->res); + port->membase = data->regs; -+ port->uartclk = clk_get_rate(data->clk); -+ port->regshift = 2; -+ port->iotype = UPIO_MEM32; + port->flags = UPF_FIXED_TYPE | UPF_FIXED_PORT | UPF_SHARE_IRQ; + port->startup = ast8250_startup; + port->shutdown = ast8250_shutdown; + port->private_data = data; + uart.bugs |= UART_BUG_TXRACE; + ++ rc = uart_read_port_properties(port); ++ if (rc) ++ return rc; ++ ++ port->type = (data->is_vuart) ? PORT_ASPEED_VUART : PORT_16550A; ++ port->handle_irq = ast8250_handle_irq; ++ port->uartclk = clk_get_rate(data->clk); ++ ++ uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE; ++ + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) { + dev_err(dev, "failed to register 8250 port\n"); @@ -85475,12 +87730,12 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + +static void ast8250_remove(struct platform_device *pdev) +{ -+ struct ast8250_data *data = platform_get_drvdata(pdev); ++ struct ast8250_data *data = platform_get_drvdata(pdev); + + if (data->is_vuart) + ast8250_vuart_set_enable(data, false); + -+ serial8250_unregister_port(data->line); ++ serial8250_unregister_port(data->line); +} + +static const struct dev_pm_ops ast8250_pm_ops = { @@ -85509,63 +87764,9 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +MODULE_AUTHOR("Chia-Wei Wang "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Aspeed UART Driver"); -diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig ---- a/drivers/tty/serial/8250/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/tty/serial/8250/Kconfig 2025-12-23 10:16:08.799239284 +0000 -@@ -256,6 +256,15 @@ - To compile this driver as a module, choose M here: the module - will be called 8250_accent. - -+config SERIAL_8250_ASPEED -+ tristate "Aspeed UART" -+ depends on SERIAL_8250 && ARCH_ASPEED -+ select ASPEED_UDMA -+ help -+ If you have a system using an Aspeed AST26xx SoCs and wish to -+ make use of its 16550A-compatible UART devices with DMA support, -+ say Y to this option. If unsure, say N. -+ - config SERIAL_8250_ASPEED_VUART - tristate "Aspeed Virtual UART" - depends on SERIAL_8250 -diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile ---- a/drivers/tty/serial/8250/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/tty/serial/8250/Makefile 2025-12-23 10:16:12.776172591 +0000 -@@ -21,6 +21,7 @@ - obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o - obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o - obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o -+obj-$(CONFIG_SERIAL_8250_ASPEED) += 8250_aspeed.o - obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o - obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o - obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o -diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig ---- a/drivers/ufs/host/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/ufs/host/Kconfig 2025-12-23 10:16:09.263231503 +0000 -@@ -142,3 +142,12 @@ - - Select this if you have UFS controller on Unisoc chipset. - If unsure, say N. -+ -+config SCSI_UFS_ASPEED -+ tristate "Aspeed specific hooks to UFS controller platform driver" -+ depends on SCSI_UFSHCD_PLATFORM -+ help -+ This selects the Aspeed specific additions to UFSHCD platform driver. -+ -+ Selects this if you have Aspeed platform with UFS controller. -+ If unsure, say N. -diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile ---- a/drivers/ufs/host/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/ufs/host/Makefile 2025-12-23 10:16:13.396162194 +0000 -@@ -12,3 +12,4 @@ - obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o - obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o - obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o -+obj-$(CONFIG_SCSI_UFS_ASPEED) += ufs-aspeed.o diff --git a/drivers/ufs/host/ufs-aspeed.c b/drivers/ufs/host/ufs-aspeed.c --- a/drivers/ufs/host/ufs-aspeed.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/ufs/host/ufs-aspeed.c 2025-12-23 10:16:21.026034312 +0000 ++++ b/drivers/ufs/host/ufs-aspeed.c 2026-09-09 15:51:44.608239734 +0000 @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (C) 2019 ASPEED Technology Inc. */ @@ -85993,8 +88194,8 @@ diff --git a/drivers/ufs/host/ufs-aspeed.c b/drivers/ufs/host/ufs-aspeed.c +MODULE_DESCRIPTION("Aspeed UFS host controller platform driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig b/drivers/usb/gadget/udc/aspeed-vhub/Kconfig ---- a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed-vhub/Kconfig 2025-12-23 10:16:21.160032066 +0000 +--- a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/Kconfig 2026-09-09 15:51:44.747237633 +0000 @@ -4,5 +4,6 @@ depends on ARCH_ASPEED || COMPILE_TEST depends on USB_LIBCOMPOSITE @@ -86005,108 +88206,51 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig b/drivers/usb/gadget/udc + and AST2700 family SoCs supporting the "vHub" functionality and + USB2.0 diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/core.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c 2025-12-23 10:16:21.160032066 +0000 -@@ -23,9 +23,27 @@ +--- a/drivers/usb/gadget/udc/aspeed-vhub/core.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c 2026-09-09 15:51:44.747237633 +0000 +@@ -23,6 +23,7 @@ #include #include #include +#include -+#include #include "vhub.h" -+#define ASPEED_G7_SCU_VHUB_USB_FUNC_OFFSET 0x410 -+ -+enum ast_g7_pcie { -+ NOT_SUPPORTED, -+ PCIE_EHCI, -+ PCIE_XHCI, -+}; -+ -+struct ast_vhub_match_data { -+ enum ast_g7_pcie g7_pcie; -+ u32 usb_mode_mask; -+ u32 xhci_mode_mask; -+ u32 txfifo_fix_reg; -+ u32 txfifo_fix_val; -+}; -+ - void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, - int status) - { -@@ -239,6 +257,7 @@ +@@ -239,9 +240,24 @@ if (vhub->force_usb1) ctrl |= VHUB_CTRL_FULL_SPEED_ONLY; ++ /* Enlarge FIFO for ast2700 soc0 vhub1 */ ++ if (vhub->enlarge_fifo) ++ ctrl |= VHUB_CTRL_ENLARGE_FIFO; ++ + ctrl |= VHUB_CTRL_AUTO_REMOTE_WAKEUP; ctrl |= VHUB_CTRL_UPSTREAM_CONNECT; writel(ctrl, vhub->regs + AST_VHUB_CTRL); -@@ -253,6 +272,52 @@ - vhub->regs + AST_VHUB_IER); - } - -+static int ast_vhub_init_pcie(struct ast_vhub *vhub, const struct ast_vhub_match_data *pdata) -+{ -+ struct device *dev = &vhub->pdev->dev; -+ struct regmap *pcie_device; -+ struct regmap *scu; -+ u32 scu_usb; -+ int rc = 0; -+ -+ scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); -+ if (IS_ERR(scu)) { -+ dev_err(dev, "failed to find SCU regmap\n"); -+ return PTR_ERR(scu); -+ } ++ /* AST2700 SoC0 vhub0 only: force retry via CRC error injection ++ * when DRAM access is delayed due to bus contention. ++ */ ++ if (vhub->txfifo_retry_quirk) { ++ u32 val = readl(vhub->regs + AST_VHUB_PHY_00); + -+ regmap_read(scu, ASPEED_G7_SCU_VHUB_USB_FUNC_OFFSET, &scu_usb); -+ -+ /* Check EHCI or xHCI to virtual hub */ -+ if ((scu_usb & pdata->usb_mode_mask) == 0) { -+ pcie_device = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "aspeed,device"); -+ if (IS_ERR(pcie_device)) { -+ dev_err(dev, "failed to find PCIe device regmap\n"); -+ return PTR_ERR(pcie_device); -+ } -+ if (pdata->g7_pcie == PCIE_XHCI) { -+ /* Check PCIe xHCI or BMC xHCI to virtual hub */ -+ if ((scu_usb & pdata->xhci_mode_mask) == 0) { -+ dev_info(dev, "PCIe xHCI to vhub\n"); -+ //EnPCIaMSI_EnPCIaIntA_EnPCIaMst_EnPCIaDev -+ /* Turn on PCIe xHCI without MSI */ -+ regmap_update_bits(pcie_device, 0x70, -+ BIT(19) | BIT(11) | BIT(3), -+ BIT(19) | BIT(11) | BIT(3)); -+ } -+ } else if (pdata->g7_pcie == PCIE_EHCI) { -+ dev_info(dev, "PCIe EHCI to vhub\n"); -+ //EnPCIaMSI_EnPCIaIntA_EnPCIaMst_EnPCIaDev -+ /* Turn on PCIe EHCI without MSI */ -+ regmap_update_bits(pcie_device, 0x70, -+ BIT(18) | BIT(10) | BIT(2), -+ BIT(18) | BIT(10) | BIT(2)); -+ } ++ val |= AST_VHUB0_FIFO_FORCE_RETRY; ++ writel(val, vhub->regs + AST_VHUB_PHY_00); + } -+ return rc; -+} + - static void ast_vhub_remove(struct platform_device *pdev) - { - struct ast_vhub *vhub = platform_get_drvdata(pdev); -@@ -280,6 +345,9 @@ + /* Enable some interrupts */ + writel(VHUB_IRQ_HUB_EP0_IN_ACK_STALL | + VHUB_IRQ_HUB_EP0_OUT_ACK_STALL | +@@ -280,6 +296,8 @@ if (vhub->clk) clk_disable_unprepare(vhub->clk); -+ if (vhub->rst) -+ reset_control_assert(vhub->rst); ++ reset_control_assert(vhub->rst); + spin_unlock_irqrestore(&vhub->lock, flags); if (vhub->ep0_bufs) -@@ -291,6 +359,61 @@ +@@ -291,9 +309,65 @@ vhub->ep0_bufs = NULL; } @@ -86168,44 +88312,31 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ static int ast_vhub_probe(struct platform_device *pdev) { enum usb_device_speed max_speed; -@@ -298,11 +421,19 @@ ++ const u64 *dma_mask_ptr; + struct ast_vhub *vhub; struct resource *res; int i, rc = 0; - const struct device_node *np = pdev->dev.of_node; -+ const struct ast_vhub_match_data *pdata; -+ u32 val; - - vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL); - if (!vhub) +@@ -323,6 +397,10 @@ + if (!vhub->epns) return -ENOMEM; -+ pdata = of_device_get_match_data(&pdev->dev); -+ if (IS_ERR(pdata)) { -+ dev_err(&pdev->dev, "Couldn't get match data\n"); -+ return -ENODEV; -+ } ++ vhub->enlarge_fifo = of_property_read_bool(np, "aspeed,enlarge-fifo"); ++ vhub->txfifo_retry_quirk = ++ of_property_read_bool(np, "aspeed,txfifo-retry-quirk"); + - rc = of_property_read_u32(np, "aspeed,vhub-downstream-ports", - &vhub->max_ports); - if (rc < 0) -@@ -337,6 +468,13 @@ - - platform_set_drvdata(pdev, vhub); + spin_lock_init(&vhub->lock); + vhub->pdev = pdev; + vhub->port_irq_mask = GENMASK(VHUB_IRQ_DEV1_BIT + vhub->max_ports - 1, +@@ -348,6 +426,21 @@ + goto err; + } + vhub->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); -+ + if (IS_ERR(vhub->rst)) { + rc = PTR_ERR(vhub->rst); + goto err; + } + - vhub->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(vhub->clk)) { - rc = PTR_ERR(vhub->clk); -@@ -348,6 +486,28 @@ - goto err; - } - + if (vhub->rst) { + mdelay(10); + rc = reset_control_deassert(vhub->rst); @@ -86213,127 +88344,54 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ + goto err; + } + -+ if (pdata->g7_pcie != NOT_SUPPORTED) { -+ rc = ast_vhub_init_pcie(vhub, pdata); -+ if (rc) -+ goto err; -+ -+ /* For G7 PortA/B, enable the option of TXFIFO fix. -+ * It forces the CRC error for a re-try when vHub cannot fetch DRAM in time. -+ */ -+ val = readl(vhub->regs + pdata->txfifo_fix_reg); -+ writel(pdata->txfifo_fix_val | val, -+ vhub->regs + pdata->txfifo_fix_reg); -+ } -+ + ast_vhub_init_uart(&pdev->dev, vhub); + /* Check if we need to limit the HW to USB1 */ max_speed = usb_get_maximum_speed(&pdev->dev); if (max_speed != USB_SPEED_UNKNOWN && max_speed < USB_SPEED_HIGH) -@@ -370,6 +530,12 @@ +@@ -370,6 +463,13 @@ goto err; } -+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_warn(&pdev->dev, "No suitable DMA available\n"); -+ goto err; ++ dma_mask_ptr = (u64 *)of_device_get_match_data(&pdev->dev); ++ if (dma_mask_ptr) { ++ rc = dma_coerce_mask_and_coherent(&pdev->dev, *dma_mask_ptr); ++ if (rc) ++ goto err; + } + /* * Allocate DMA buffers for all EP0s in one chunk, * one per port and one for the vHub itself -@@ -412,15 +578,86 @@ +@@ -412,15 +512,25 @@ return rc; } -+static const struct ast_vhub_match_data aspeed_vhub_match_data = { -+ .g7_pcie = NOT_SUPPORTED, -+}; -+ -+static const struct ast_vhub_match_data aspeed_g7_vhuba0_match_data = { -+ .g7_pcie = PCIE_EHCI, -+ .usb_mode_mask = GENMASK(25, 24), -+ .xhci_mode_mask = 0, -+ .txfifo_fix_reg = 0x800, -+ .txfifo_fix_val = BIT(13), -+}; -+ -+static const struct ast_vhub_match_data aspeed_g7_vhubb0_match_data = { -+ .g7_pcie = PCIE_EHCI, -+ .usb_mode_mask = GENMASK(29, 28), -+ .xhci_mode_mask = 0, -+ .txfifo_fix_reg = 0x800, -+ .txfifo_fix_val = BIT(13), -+}; -+ -+static const struct ast_vhub_match_data aspeed_g7_vhuba1_match_data = { -+ .g7_pcie = PCIE_XHCI, -+ .usb_mode_mask = GENMASK(3, 2), -+ .xhci_mode_mask = BIT_MASK(9), -+ .txfifo_fix_reg = 0x80C, -+ .txfifo_fix_val = BIT(31), -+}; -+ -+static const struct ast_vhub_match_data aspeed_g7_vhubb1_match_data = { -+ .g7_pcie = PCIE_XHCI, -+ .usb_mode_mask = GENMASK(7, 6), -+ .xhci_mode_mask = BIT_MASK(10), -+ .txfifo_fix_reg = 0x80C, -+ .txfifo_fix_val = BIT(31), -+}; -+ -+static const struct ast_vhub_match_data aspeed_g7_vhubc_match_data = { -+ .g7_pcie = NOT_SUPPORTED, -+}; -+ -+static const struct ast_vhub_match_data aspeed_g7_vhubd_match_data = { -+ .g7_pcie = NOT_SUPPORTED, -+}; ++static const u64 dma_mask_32 = DMA_BIT_MASK(32); ++static const u64 dma_mask_64 = DMA_BIT_MASK(64); + static const struct of_device_id ast_vhub_dt_ids[] = { { .compatible = "aspeed,ast2400-usb-vhub", -+ .data = &aspeed_vhub_match_data, ++ .data = &dma_mask_32, }, { .compatible = "aspeed,ast2500-usb-vhub", -+ .data = &aspeed_vhub_match_data, ++ .data = &dma_mask_32, }, { .compatible = "aspeed,ast2600-usb-vhub", -+ .data = &aspeed_vhub_match_data, -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb-vhuba0", -+ .data = &aspeed_g7_vhuba0_match_data, -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb-vhubb0", -+ .data = &aspeed_g7_vhubb0_match_data, -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb-vhuba1", -+ .data = &aspeed_g7_vhuba1_match_data, ++ .data = &dma_mask_32, + }, + { -+ .compatible = "aspeed,ast2700-usb-vhubb1", -+ .data = &aspeed_g7_vhubb1_match_data, -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb-vhubc", -+ .data = &aspeed_g7_vhubc_match_data, -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb-vhubd", -+ .data = &aspeed_g7_vhubd_match_data, ++ .compatible = "aspeed,ast2700-usb-vhub", ++ .data = &dma_mask_64, }, { } }; diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c 2025-12-23 10:16:21.160032066 +0000 +--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c 2026-09-09 15:51:44.747237633 +0000 @@ -116,10 +116,14 @@ if (wValue == USB_DEVICE_REMOTE_WAKEUP) { @@ -86361,8 +88419,8 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/a } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c 2025-12-23 10:16:21.160032066 +0000 +--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c 2026-09-09 15:51:44.747237633 +0000 @@ -340,7 +340,9 @@ struct ast_vhub *vhub = ep->vhub; unsigned long flags; @@ -86464,8 +88522,8 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/a struct ast_vhub_ep *ast_vhub_alloc_epn(struct ast_vhub_dev *d, u8 addr) diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c 2025-12-23 10:16:21.160032066 +0000 +--- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c 2026-09-09 15:51:44.747237633 +0000 @@ -221,9 +221,8 @@ EPDBG(ep, "Hub remote wakeup %s\n", is_set ? "enabled" : "disabled"); @@ -86511,9 +88569,38 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/a return ast_vhub_simple_reply(ep, diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h ---- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h 2025-12-23 10:16:21.160032066 +0000 -@@ -199,6 +199,14 @@ +--- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h 2026-09-09 15:51:44.747237633 +0000 +@@ -29,12 +29,14 @@ + #define AST_VHUB_EP1_STS_CHG 0x3C /* Endpoint 1 Status Change Bitmap Data */ + #define AST_VHUB_SETUP0 0x80 /* Root Device Setup Data Buffer0 */ + #define AST_VHUB_SETUP1 0x84 /* Root Device Setup Data Buffer1 */ ++#define AST_VHUB_PHY_00 0x800 /* USB PHY Control/Status #1 */ + + /* Main control reg */ + #define VHUB_CTRL_PHY_CLK (1 << 31) + #define VHUB_CTRL_PHY_LOOP_TEST (1 << 25) + #define VHUB_CTRL_DN_PWN (1 << 24) + #define VHUB_CTRL_DP_PWN (1 << 23) ++#define VHUB_CTRL_ENLARGE_FIFO (1 << 21) + #define VHUB_CTRL_LONG_DESC (1 << 18) + #define VHUB_CTRL_ISO_RSP_CTRL (1 << 17) + #define VHUB_CTRL_SPLIT_IN (1 << 16) +@@ -184,6 +186,13 @@ + #define VHUB_EP_DMA_SET_CPU_WPTR(x) (x) + #define VHUB_EP_DMA_SINGLE_KICK (1 << 0) /* WPTR = 1 for single mode */ + ++/******************************************* ++ * * ++ * PHY Control/Status register definitions * ++ * * ++ *******************************************/ ++#define AST_VHUB0_FIFO_FORCE_RETRY BIT(13) ++ + /******************************* + * * + * DMA descriptors definitions * +@@ -199,6 +208,14 @@ #define VHUB_DSC1_IN_SET_LEN(x) ((x) & 0xfff) #define VHUB_DSC1_IN_LEN(x) ((x) & 0xfff) @@ -86528,7 +88615,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/ /**************************************** * * * Data structures and misc definitions * -@@ -218,6 +226,8 @@ +@@ -218,6 +235,8 @@ * values are 256 and 32) */ @@ -86537,17 +88624,24 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/ struct ast_vhub; struct ast_vhub_dev; -@@ -388,6 +398,8 @@ +@@ -388,6 +407,7 @@ spinlock_t lock; struct work_struct wake_work; struct clk *clk; + struct reset_control *rst; -+ /* EP0 DMA buffers allocated in one chunk */ void *ep0_bufs; -@@ -419,6 +431,7 @@ +@@ -417,8 +437,15 @@ + /* Force full speed only */ + bool force_usb1 : 1; ++ /* Enlarge FIFO for ast2700 soc0 vhub1 */ ++ bool enlarge_fifo : 1; ++ ++ /* Force TXFIFO retry when is DRAM busy for ast2700 soc0 vhub0 */ ++ bool txfifo_retry_quirk : 1; ++ /* Upstream bus speed captured at bus reset */ unsigned int speed; + u8 current_config; @@ -86555,8 +88649,8 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/ /* Standard USB Descriptors of the vhub. */ struct usb_device_descriptor vhub_dev_desc; diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c ---- a/drivers/usb/gadget/udc/aspeed_udc.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/usb/gadget/udc/aspeed_udc.c 2025-12-23 10:16:21.115032820 +0000 +--- a/drivers/usb/gadget/udc/aspeed_udc.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/usb/gadget/udc/aspeed_udc.c 2026-09-09 15:51:44.703238298 +0000 @@ -156,7 +156,7 @@ #define AST_EP_DMA_DESC_PID_DATA1 (2 << 14) #define AST_EP_DMA_DESC_PID_MDATA (3 << 14) @@ -86748,8 +88842,8 @@ diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { ep = &udc->ep[i]; diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c ---- a/drivers/watchdog/aspeed_wdt.c 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/watchdog/aspeed_wdt.c 2025-12-23 10:16:21.077033457 +0000 +--- a/drivers/watchdog/aspeed_wdt.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/watchdog/aspeed_wdt.c 2026-09-09 15:51:44.660238948 +0000 @@ -35,6 +35,8 @@ u32 irq_shift; u32 irq_mask; @@ -86982,7 +89076,7 @@ diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c aspeed_wdt_update_bootstatus(pdev, wdt); diff --git a/include/dt-bindings/clock/aspeed,ast1700-clk.h b/include/dt-bindings/clock/aspeed,ast1700-clk.h --- a/include/dt-bindings/clock/aspeed,ast1700-clk.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/clock/aspeed,ast1700-clk.h 2025-12-23 10:16:21.275030139 +0000 ++++ b/include/dt-bindings/clock/aspeed,ast1700-clk.h 2026-09-09 15:51:44.868235805 +0000 @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -87083,7 +89177,7 @@ diff --git a/include/dt-bindings/clock/aspeed,ast1700-clk.h b/include/dt-binding +#endif diff --git a/include/dt-bindings/clock/aspeed,ast1800-clk.h b/include/dt-bindings/clock/aspeed,ast1800-clk.h --- a/include/dt-bindings/clock/aspeed,ast1800-clk.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/clock/aspeed,ast1800-clk.h 2025-12-23 10:16:21.285029971 +0000 ++++ b/include/dt-bindings/clock/aspeed,ast1800-clk.h 2026-09-09 15:51:44.878235654 +0000 @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -87191,8 +89285,8 @@ diff --git a/include/dt-bindings/clock/aspeed,ast1800-clk.h b/include/dt-binding +#endif diff --git a/include/dt-bindings/clock/aspeed,ast2700-scu.h b/include/dt-bindings/clock/aspeed,ast2700-scu.h --- a/include/dt-bindings/clock/aspeed,ast2700-scu.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/clock/aspeed,ast2700-scu.h 2025-12-23 10:16:21.289029904 +0000 -@@ -0,0 +1,167 @@ ++++ b/include/dt-bindings/clock/aspeed,ast2700-scu.h 2026-09-09 15:51:44.883235578 +0000 +@@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Device Tree binding constants for AST2700 clock controller. @@ -87358,11 +89452,13 @@ diff --git a/include/dt-bindings/clock/aspeed,ast2700-scu.h b/include/dt-binding +#define SCU1_CLK_GATE_PORTDUSB2CLK 85 +#define SCU1_CLK_GATE_LTPI1TXCLK 86 +#define SCU1_CLK_I3C 87 ++#define SCU1_CLK_HPLL_DIV4 88 ++#define SCU1_CLK_PECI 89 + +#endif diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h ---- a/include/dt-bindings/clock/aspeed-clock.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/dt-bindings/clock/aspeed-clock.h 2025-12-23 10:16:21.280030055 +0000 +--- a/include/dt-bindings/clock/aspeed-clock.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/dt-bindings/clock/aspeed-clock.h 2026-09-09 15:51:44.873235729 +0000 @@ -53,5 +53,6 @@ #define ASPEED_RESET_AHB 8 #define ASPEED_RESET_CRT1 9 @@ -87371,8 +89467,8 @@ diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/cloc #endif diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h ---- a/include/dt-bindings/clock/ast2600-clock.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/dt-bindings/clock/ast2600-clock.h 2025-12-23 10:16:21.294029820 +0000 +--- a/include/dt-bindings/clock/ast2600-clock.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/dt-bindings/clock/ast2600-clock.h 2026-09-09 15:51:44.888235503 +0000 @@ -72,7 +72,7 @@ #define ASPEED_CLK_D1CLK 55 #define ASPEED_CLK_VCLK 56 @@ -87418,7 +89514,7 @@ diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clo #define ASPEED_RESET_AHB 1 diff --git a/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h b/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h --- a/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h 2025-12-23 10:16:21.299029736 +0000 ++++ b/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h 2026-09-09 15:51:44.893235427 +0000 @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -87442,8 +89538,8 @@ diff --git a/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h b/include/ + +#endif /* _DT_BINDINGS_INTERRUPT_CONTROLLER_ASPEED_E2M_IC_H_ */ diff --git a/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h b/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h ---- a/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h 2025-12-23 10:16:21.304029653 +0000 +--- a/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h 2026-09-09 15:51:44.898235352 +0000 @@ -20,4 +20,18 @@ #define ASPEED_AST2600_SCU_IC1_LPC_RESET_LO_TO_HI 0 #define ASPEED_AST2600_SCU_IC1_LPC_RESET_HI_TO_LO 1 @@ -87465,7 +89561,7 @@ diff --git a/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h b/include/ #endif /* _DT_BINDINGS_INTERRUPT_CONTROLLER_ASPEED_SCU_IC_H_ */ diff --git a/include/dt-bindings/reset/aspeed,ast1700-reset.h b/include/dt-bindings/reset/aspeed,ast1700-reset.h --- a/include/dt-bindings/reset/aspeed,ast1700-reset.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/reset/aspeed,ast1700-reset.h 2025-12-23 10:16:21.317029435 +0000 ++++ b/include/dt-bindings/reset/aspeed,ast1700-reset.h 2026-09-09 15:51:44.913235125 +0000 @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -87538,7 +89634,7 @@ diff --git a/include/dt-bindings/reset/aspeed,ast1700-reset.h b/include/dt-bindi +#endif /* _MACH_ASPEED_AST1700_RESET_H_ */ diff --git a/include/dt-bindings/reset/aspeed,ast1800-reset.h b/include/dt-bindings/reset/aspeed,ast1800-reset.h --- a/include/dt-bindings/reset/aspeed,ast1800-reset.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/reset/aspeed,ast1800-reset.h 2025-12-23 10:16:21.326029284 +0000 ++++ b/include/dt-bindings/reset/aspeed,ast1800-reset.h 2026-09-09 15:51:44.923234974 +0000 @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -87603,7 +89699,7 @@ diff --git a/include/dt-bindings/reset/aspeed,ast1800-reset.h b/include/dt-bindi +#endif /* _MACH_ASPEED_AST1800_RESET_H_ */ diff --git a/include/dt-bindings/reset/aspeed,ast2700-scu.h b/include/dt-bindings/reset/aspeed,ast2700-scu.h --- a/include/dt-bindings/reset/aspeed,ast2700-scu.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/dt-bindings/reset/aspeed,ast2700-scu.h 2025-12-23 10:16:21.322029351 +0000 ++++ b/include/dt-bindings/reset/aspeed,ast2700-scu.h 2026-09-09 15:51:44.918235049 +0000 @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -87731,8 +89827,8 @@ diff --git a/include/dt-bindings/reset/aspeed,ast2700-scu.h b/include/dt-binding + +#endif /* _MACH_ASPEED_AST2700_RESET_H_ */ diff --git a/include/dt-bindings/watchdog/aspeed-wdt.h b/include/dt-bindings/watchdog/aspeed-wdt.h ---- a/include/dt-bindings/watchdog/aspeed-wdt.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/dt-bindings/watchdog/aspeed-wdt.h 2025-12-23 10:16:21.313029502 +0000 +--- a/include/dt-bindings/watchdog/aspeed-wdt.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/dt-bindings/watchdog/aspeed-wdt.h 2026-09-09 15:51:44.908235200 +0000 @@ -89,4 +89,142 @@ #define AST2600_WDT_RESET2_DEFAULT 0x03fffff1 @@ -87878,7 +89974,7 @@ diff --git a/include/dt-bindings/watchdog/aspeed-wdt.h b/include/dt-bindings/wat #endif diff --git a/include/linux/aspeed-mctp.h b/include/linux/aspeed-mctp.h --- a/include/linux/aspeed-mctp.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/linux/aspeed-mctp.h 2025-12-23 10:16:21.266030290 +0000 ++++ b/include/linux/aspeed-mctp.h 2026-09-09 15:51:44.858235956 +0000 @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2025 ASPEED Tech */ @@ -88037,90 +90133,9 @@ diff --git a/include/linux/aspeed-mctp.h b/include/linux/aspeed-mctp.h +int aspeed_mctp_register_default_handler(struct mctp_client *client); + +#endif /* __LINUX_ASPEED_MCTP_H */ -diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h ---- a/include/linux/clk-provider.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/linux/clk-provider.h 2025-12-23 10:16:22.000017988 +0000 -@@ -623,6 +623,24 @@ - NULL, (flags), (reg), (bit_idx), \ - (clk_gate_flags), (lock)) - /** -+ * devm_clk_hw_register_gate_parent_hw - register a gate clock with the clock -+ * framework -+ * @dev: device that is registering this clock -+ * @name: name of this clock -+ * @parent_hw: pointer to parent clk -+ * @flags: framework-specific flags for this clock -+ * @reg: register address to control gating of this clock -+ * @bit_idx: which bit in the register controls gating of this clock -+ * @clk_gate_flags: gate-specific flags for this clock -+ * @lock: shared register lock for this clock -+ */ -+#define devm_clk_hw_register_gate_parent_hw(dev, name, parent_hw, flags, \ -+ reg, bit_idx, clk_gate_flags, \ -+ lock) \ -+ __devm_clk_hw_register_gate((dev), NULL, (name), NULL, (parent_hw), \ -+ NULL, (flags), (reg), (bit_idx), \ -+ (clk_gate_flags), (lock)) -+/** - * devm_clk_hw_register_gate_parent_data - register a gate clock with the - * clock framework - * @dev: device that is registering this clock -diff --git a/include/linux/mctp-pcie-vdm.h b/include/linux/mctp-pcie-vdm.h ---- a/include/linux/mctp-pcie-vdm.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/linux/mctp-pcie-vdm.h 2025-12-23 10:16:21.973018440 +0000 -@@ -0,0 +1,36 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * mctp-pcie-vdm.h - MCTP-over-PCIe-VDM (DMTF DSP0238) transport binding Interface -+ * for PCIe VDM devices to register and implement. -+ * -+ */ -+ -+#ifndef __LINUX_MCTP_PCIE_VDM_H -+#define __LINUX_MCTP_PCIE_VDM_H -+ -+#include -+#include -+ -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+ -+/** -+ * @send_packet: referenced to send packets with PCIe VDM header packed. -+ * @recv_packet: referenced multiple times until no RX packet to be handled. -+ * received pointer shall start from the PCIe VDM header. -+ * @free_packet: referenced when the packet is processed and okay to be freed. -+ * @uninit: uninitialize the device. -+ */ -+struct mctp_pcie_vdm_ops { -+ int (*send_packet)(struct device *dev, u8 *data, size_t len); -+ u8 *(*recv_packet)(struct device *dev); -+ void (*free_packet)(void *packet); -+ void (*uninit)(struct device *dev); -+}; -+ -+struct net_device *mctp_pcie_vdm_add_dev(struct device *dev, -+ const struct mctp_pcie_vdm_ops *ops); -+void mctp_pcie_vdm_receive_packet(struct net_device *ndev); -+void mctp_pcie_vdm_remove_dev(struct net_device *ndev); -+ -+#endif /* CONFIG_MCTP_TRANSPORT_PCIE_VDM */ -+#endif /* __LINUX_MCTP_PCIE_VDM_H */ -diff --git a/include/linux/pwm.h b/include/linux/pwm.h ---- a/include/linux/pwm.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/linux/pwm.h 2025-12-23 10:16:22.035017401 +0000 -@@ -405,6 +405,9 @@ - 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) - -+struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, -+ unsigned int index, const char *label); -+ - struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *chip, - const struct of_phandle_args *args); - struct pwm_device *of_pwm_single_xlate(struct pwm_chip *chip, diff --git a/include/linux/soc/aspeed/aspeed-otp.h b/include/linux/soc/aspeed/aspeed-otp.h --- a/include/linux/soc/aspeed/aspeed-otp.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/linux/soc/aspeed/aspeed-otp.h 2025-12-23 10:16:21.257030440 +0000 ++++ b/include/linux/soc/aspeed/aspeed-otp.h 2026-09-09 15:51:44.848236107 +0000 @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* @@ -88136,12 +90151,12 @@ diff --git a/include/linux/soc/aspeed/aspeed-otp.h b/include/linux/soc/aspeed/as +#endif /* _LINUX_ASPEED_OTP_H */ diff --git a/include/linux/soc/aspeed/aspeed-udma.h b/include/linux/soc/aspeed/aspeed-udma.h --- a/include/linux/soc/aspeed/aspeed-udma.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/linux/soc/aspeed/aspeed-udma.h 2025-12-23 10:16:21.252030524 +0000 -@@ -0,0 +1,28 @@ ++++ b/include/linux/soc/aspeed/aspeed-udma.h 2026-09-09 15:51:44.843236183 +0000 +@@ -0,0 +1,26 @@ +#ifndef __ASPEED_UDMA_H__ +#define __ASPEED_UDMA_H__ + -+typedef void (*aspeed_udma_cb_t)(int fifo_rwptr, void *id); ++typedef void (*aspeed_udma_cb_t)(int rb_rwptr, void *id); + +enum aspeed_udma_ops { + ASPEED_UDMA_OP_ENABLE, @@ -88155,11 +90170,9 @@ diff --git a/include/linux/soc/aspeed/aspeed-udma.h b/include/linux/soc/aspeed/a +void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op); +void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op); + -+int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, -+ struct kfifo *fifo, u32 fifo_sz, ++int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool en_tmout); -+int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, -+ struct kfifo *fifo, u32 fifo_sz, ++int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool en_tmout); + +int aspeed_udma_free_tx_chan(u32 ch_no); @@ -88168,7 +90181,7 @@ diff --git a/include/linux/soc/aspeed/aspeed-udma.h b/include/linux/soc/aspeed/a +#endif diff --git a/include/soc/aspeed/reset-aspeed.h b/include/soc/aspeed/reset-aspeed.h --- a/include/soc/aspeed/reset-aspeed.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/soc/aspeed/reset-aspeed.h 2025-12-23 10:16:21.214031161 +0000 ++++ b/include/soc/aspeed/reset-aspeed.h 2026-09-09 15:51:44.802236802 +0000 @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* @@ -88191,139 +90204,9 @@ diff --git a/include/soc/aspeed/reset-aspeed.h b/include/soc/aspeed/reset-aspeed +#endif /* if IS_ENABLED(CONFIG_RESET_ASPEED) */ + +#endif /* __RESET_ASPEED_H__ */ -diff --git a/include/trace/events/xdma.h b/include/trace/events/xdma.h ---- a/include/trace/events/xdma.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/trace/events/xdma.h 2025-12-23 10:16:21.990018155 +0000 -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM xdma -+ -+#if !defined(_TRACE_XDMA_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _TRACE_XDMA_H -+ -+#include -+ -+TRACE_EVENT(xdma_start, -+ TP_PROTO(const struct aspeed_xdma *ctx, const struct aspeed_xdma_cmd *cmd), -+ TP_ARGS(ctx, cmd), -+ TP_STRUCT__entry(__field(bool, dir_upstream) -+ __field(unsigned int, index) -+ __field(__u64, host) -+ __field(__u64, pitch) -+ __field(__u64, cmd) -+ ), -+ TP_fast_assign(__entry->dir_upstream = ctx->upstream; -+ __entry->index = ctx->cmd_idx; -+ __entry->host = cmd->host_addr; -+ __entry->pitch = cmd->pitch; -+ __entry->cmd = cmd->cmd; -+ ), -+ TP_printk("%s cmd:%u [%08llx %016llx %016llx]", -+ __entry->dir_upstream ? "upstream" : "downstream", -+ __entry->index, -+ __entry->host, -+ __entry->pitch, -+ __entry->cmd -+ ) -+); -+ -+TRACE_EVENT(xdma_irq, -+ TP_PROTO(u32 sts), -+ TP_ARGS(sts), -+ TP_STRUCT__entry(__field(__u32, status) -+ ), -+ TP_fast_assign(__entry->status = sts; -+ ), -+ TP_printk("sts:%08x", -+ __entry->status -+ ) -+); -+ -+TRACE_EVENT(xdma_reset, -+ TP_PROTO(const struct aspeed_xdma *ctx), -+ TP_ARGS(ctx), -+ TP_STRUCT__entry(__field(bool, dir_upstream) -+ __field(bool, in_progress) -+ ), -+ TP_fast_assign(__entry->dir_upstream = ctx->upstream; -+ __entry->in_progress = -+ ctx->current_client ? ctx->current_client->in_progress : false; -+ ), -+ TP_printk("%sin progress%s", -+ __entry->in_progress ? "" : "not ", -+ __entry->in_progress ? (__entry->dir_upstream ? -+ " upstream" : " downstream") : "" -+ ) -+); -+ -+TRACE_EVENT(xdma_perst, -+ TP_PROTO(const struct aspeed_xdma *ctx), -+ TP_ARGS(ctx), -+ TP_STRUCT__entry(__field(bool, in_reset) -+ ), -+ TP_fast_assign(__entry->in_reset = ctx->in_reset; -+ ), -+ TP_printk("%s", -+ __entry->in_reset ? "in reset" : "" -+ ) -+); -+ -+TRACE_EVENT(xdma_unmap, -+ TP_PROTO(const struct aspeed_xdma_client *client), -+ TP_ARGS(client), -+ TP_STRUCT__entry(__field(__u32, phys) -+ __field(__u32, size) -+ ), -+ TP_fast_assign(__entry->phys = client->phys; -+ __entry->size = client->size; -+ ), -+ TP_printk("p:%08x s:%08x", -+ __entry->phys, -+ __entry->size -+ ) -+); -+ -+TRACE_EVENT(xdma_mmap_error, -+ TP_PROTO(const struct aspeed_xdma_client *client, unsigned long vm_start), -+ TP_ARGS(client, vm_start), -+ TP_STRUCT__entry(__field(__u32, phys) -+ __field(__u32, size) -+ __field(unsigned long, vm_start) -+ ), -+ TP_fast_assign(__entry->phys = client->phys; -+ __entry->size = client->size; -+ __entry->vm_start = vm_start; -+ ), -+ TP_printk("p:%08x s:%08x v:%08lx", -+ __entry->phys, -+ __entry->size, -+ __entry->vm_start -+ ) -+); -+ -+TRACE_EVENT(xdma_mmap, -+ TP_PROTO(const struct aspeed_xdma_client *client), -+ TP_ARGS(client), -+ TP_STRUCT__entry(__field(__u32, phys) -+ __field(__u32, size) -+ ), -+ TP_fast_assign(__entry->phys = client->phys; -+ __entry->size = client->size; -+ ), -+ TP_printk("p:%08x s:%08x", -+ __entry->phys, -+ __entry->size -+ ) -+); -+ -+#endif /* _TRACE_XDMA_H */ -+ -+#include diff --git a/include/uapi/linux/aspeed-mctp.h b/include/uapi/linux/aspeed-mctp.h --- a/include/uapi/linux/aspeed-mctp.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/uapi/linux/aspeed-mctp.h 2025-12-23 10:16:21.247030608 +0000 ++++ b/include/uapi/linux/aspeed-mctp.h 2026-09-09 15:51:44.838236258 +0000 @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2020 Intel Corporation */ @@ -88462,8 +90345,8 @@ diff --git a/include/uapi/linux/aspeed-mctp.h b/include/uapi/linux/aspeed-mctp.h + +#endif /* _UAPI_LINUX_ASPEED_MCTP_H */ diff --git a/include/uapi/linux/aspeed-video.h b/include/uapi/linux/aspeed-video.h ---- a/include/uapi/linux/aspeed-video.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/uapi/linux/aspeed-video.h 2025-12-23 10:16:21.223031010 +0000 +--- a/include/uapi/linux/aspeed-video.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/uapi/linux/aspeed-video.h 2026-09-09 15:51:44.812236651 +0000 @@ -8,6 +8,15 @@ #include @@ -88482,7 +90365,7 @@ diff --git a/include/uapi/linux/aspeed-video.h b/include/uapi/linux/aspeed-video diff --git a/include/uapi/linux/aspeed-xdma.h b/include/uapi/linux/aspeed-xdma.h --- a/include/uapi/linux/aspeed-xdma.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/uapi/linux/aspeed-xdma.h 2025-12-23 10:16:21.233030843 +0000 ++++ b/include/uapi/linux/aspeed-xdma.h 2026-09-09 15:51:44.822236500 +0000 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* Copyright IBM Corp 2019 */ @@ -88528,7 +90411,7 @@ diff --git a/include/uapi/linux/aspeed-xdma.h b/include/uapi/linux/aspeed-xdma.h +#endif /* _UAPI_LINUX_ASPEED_XDMA_H_ */ diff --git a/include/uapi/linux/otp_ast2600.h b/include/uapi/linux/otp_ast2600.h --- a/include/uapi/linux/otp_ast2600.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/uapi/linux/otp_ast2600.h 2025-12-23 10:16:21.238030759 +0000 ++++ b/include/uapi/linux/otp_ast2600.h 2026-09-09 15:51:44.828236409 +0000 @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* @@ -88571,7 +90454,7 @@ diff --git a/include/uapi/linux/otp_ast2600.h b/include/uapi/linux/otp_ast2600.h +#endif /* _UAPI_LINUX_OTP_AST2600_H */ diff --git a/include/uapi/linux/otp_ast2700.h b/include/uapi/linux/otp_ast2700.h --- a/include/uapi/linux/otp_ast2700.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/uapi/linux/otp_ast2700.h 2025-12-23 10:16:21.218031094 +0000 ++++ b/include/uapi/linux/otp_ast2700.h 2026-09-09 15:51:44.807236727 +0000 @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* @@ -88620,14 +90503,3 @@ diff --git a/include/uapi/linux/otp_ast2700.h b/include/uapi/linux/otp_ast2700.h +#define ASPEED_OTP_GET_REVID _IOR(OTPIOC_BASE, 9, struct otp_revid) + +#endif /* _UAPI_LINUX_OTP_AST2700_H */ -diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h ---- a/include/uapi/linux/videodev2.h 2025-08-01 08:48:47.000000000 +0000 -+++ b/include/uapi/linux/videodev2.h 2025-12-23 10:16:22.013017770 +0000 -@@ -880,6 +880,7 @@ - /* Flags */ - #define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA 0x00000001 - #define V4L2_PIX_FMT_FLAG_SET_CSC 0x00000002 -+#define V4L2_PIX_FMT_FLAG_PARTIAL_JPG 0x00000004 - - /* - * F O R M A T E N U M E R A T I O N diff --git a/patches-sonic/0001-mmc-sdhci-cadence-Add-CN10K-eMMC-support.patch b/patches-sonic/0001-mmc-sdhci-cadence-Add-CN10K-eMMC-support.patch index aa878442f..9776e4650 100644 --- a/patches-sonic/0001-mmc-sdhci-cadence-Add-CN10K-eMMC-support.patch +++ b/patches-sonic/0001-mmc-sdhci-cadence-Add-CN10K-eMMC-support.patch @@ -2470,7 +2470,7 @@ index be1505e8c536..87022bc6d941 100644 }; static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = { -@@ -431,12 +2281,32 @@ static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = { +@@ -431,19 +2281,40 @@ static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = { .pltfm_data = { .ops = &sdhci_elba_ops, }, @@ -2494,6 +2494,15 @@ index be1505e8c536..87022bc6d941 100644 + .cdns_data = &sdhci_cdns_sd4_data, }; + static const struct sdhci_cdns_drv_data sdhci_eyeq_drv_data = { + .pltfm_data = { +- .ops = &sdhci_cdns_ops, ++ .ops = &sdhci_cdns_sd4_ops, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, ++ .cdns_data = NULL, + }; + -static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = { +static const struct sdhci_cdns_drv_data sdhci_cdns_sd6_drv_data = { + .init = sdhci_cdns_sd6_phy_probe, @@ -2698,9 +2707,9 @@ index be1505e8c536..87022bc6d941 100644 return ret; } -@@ -595,7 +2549,14 @@ static const struct of_device_id sdhci_cdns_match[] = { - .compatible = "amd,pensando-elba-sd4hc", - .data = &sdhci_elba_drv_data, +@@ -606,7 +2549,14 @@ static const struct of_device_id sdhci_cdns_match[] = { + .compatible = "mobileye,eyeq-sd4hc", + .data = &sdhci_eyeq_drv_data, }, - { .compatible = "cdns,sd4hc" }, + { diff --git a/patches-sonic/0002-arm64-dts-Update-cache-properties-for-marvell.patch b/patches-sonic/0002-arm64-dts-Update-cache-properties-for-marvell.patch deleted file mode 100644 index 4d6c1bb20..000000000 --- a/patches-sonic/0002-arm64-dts-Update-cache-properties-for-marvell.patch +++ /dev/null @@ -1,88 +0,0 @@ -From: Pierre Gondois -Date: Mon, 31 Oct 2022 10:20:16 +0100 -arm64: dts: Update cache properties for marvell - -The DeviceTree Specification v0.3 specifies that the cache node -'compatible' and 'cache-level' properties are 'required'. Cf. -s3.8 Multi-level and Shared Cache Nodes - -The recently added init_of_cache_level() function checks -these properties. Add them if missing. - -Signed-off-by: Pierre Gondois -Reviewed-by: Chris Packham -Signed-off-by: Gregory CLEMENT ---- - arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi | 1 + - arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi | 1 + - arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi | 2 ++ - arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi | 2 ++ - 4 files changed, 6 insertions(+) - -diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -index 44ed6f963..7308f7b6b 100644 ---- a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -+++ b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -@@ -49,6 +49,7 @@ cpu1: cpu@1 { - - l2: l2-cache { - compatible = "cache"; -+ cache-level = <2>; - }; - }; - -diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi -index fcab5173f..990f70303 100644 ---- a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi -+++ b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi -@@ -51,6 +51,7 @@ l2: l2-cache { - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; -+ cache-level = <2>; - }; - }; - -diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi -index 3db427122..a7b8e001c 100644 ---- a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi -+++ b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi -@@ -81,6 +81,7 @@ l2_0: l2-cache0 { - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; -+ cache-level = <2>; - }; - - l2_1: l2-cache1 { -@@ -88,6 +89,7 @@ l2_1: l2-cache1 { - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; -+ cache-level = <2>; - }; - }; - }; -diff --git a/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi -index 68782f161..7740098fd 100644 ---- a/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi -+++ b/arch/arm64/boot/dts/marvell/armada-ap807-quad.dtsi -@@ -81,6 +81,7 @@ l2_0: l2-cache0 { - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; -+ cache-level = <2>; - }; - - l2_1: l2-cache1 { -@@ -88,6 +89,7 @@ l2_1: l2-cache1 { - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; -+ cache-level = <2>; - }; - }; - }; --- -2.25.1 - diff --git a/patches-sonic/0002-aspeed-ast2700-aspeed-new-files-update-to-6.12-00.07.02.patch b/patches-sonic/0002-aspeed-ast2700-aspeed-new-files-update-to-6.12-00.07.02.patch deleted file mode 100644 index 7a91dd88f..000000000 --- a/patches-sonic/0002-aspeed-ast2700-aspeed-new-files-update-to-6.12-00.07.02.patch +++ /dev/null @@ -1,15452 +0,0 @@ -From b824ce89ad7d3dc49e95a60cda5f0381a000b004 Mon Sep 17 00:00:00 2001 -From: Chander -Date: Wed, 13 May 2026 23:09:27 +0000 -Subject: [PATCH] Aspeed specific changes - -This patch adds support for Aspeed AST2700 ARM64 SoC including: -- Device tree files for AST2700 and related boards -- Aspeed-specific drivers (pinctrl, clk, soc, crypto, etc.) -- Faraday ethernet driver support -- Kconfig and Makefile updates - -This patch targets aspeed specific changes as part of updating to kernel-6.12 -00.07.02. - -Signed-off-by: Chander - ---- - arch/arm64/Kconfig.platforms | 1 + - arch/arm64/boot/dts/aspeed/Makefile | 13 +- - arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi | 135 +- - arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi | 32 +- - arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi | 32 +- - .../boot/dts/aspeed/aspeed-ltpi1800.dtsi | 32 +- - .../arm64/boot/dts/aspeed/ast2700-ci-host.dts | 30 + - arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts | 9 +- - arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts | 24 +- - arch/arm64/boot/dts/aspeed/ast2700-evb.dts | 35 +- - .../boot/dts/aspeed/ast2700-evbeeprom.dts | 4 - - arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts | 4 - - arch/arm64/boot/dts/aspeed/ast2700-fpga.dts | 4 - - arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts | 4 - - .../boot/dts/aspeed/ast2700-reserved-mem.dtsi | 2 + - arch/arm64/boot/dts/aspeed/ast2700-slt.dts | 13 - - .../boot/dts/aspeed/ast2700a1-ci-host.dts | 127 ++ - .../arm64/boot/dts/aspeed/ast2700a1-dcscm.dts | 974 +++++++++++++ - .../ast2700a1-dcscm_ast1700a1-evb-dual.dts | 218 +++ - .../aspeed/ast2700a1-dcscm_ast1700a1-evb.dts | 456 ++++++ - .../aspeed/ast2700a1-dcscm_ast1800-evb.dts | 436 ++++++ - .../boot/dts/aspeed/ast2700a1-evb-256-abr.dts | 40 + - .../boot/dts/aspeed/ast2700a1-evb-s0.dts | 367 +++++ - .../boot/dts/aspeed/ast2700a1-evb-s1.dts | 481 +++++++ - arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts | 1265 +++++++++++++++++ - arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts | 48 + - arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts | 220 +++ - crypto/Makefile | 1 + - crypto/aspeed_crypt.c | 264 ++++ - drivers/bus/aspeed-ltpi.c | 919 +++++++++++- - drivers/bus/aspeed-ltpi.h | 276 ++++ - drivers/clk/clk-ast1700.c | 18 +- - drivers/clk/clk-ast2700.c | 90 -- - drivers/crypto/aspeed/aspeed-rsss-rsa.c | 51 +- - drivers/crypto/aspeed/aspeed-rsss.h | 6 +- - drivers/gpu/drm/aspeed/aspeed_gfx.h | 5 + - drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 15 +- - drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 17 + - drivers/i2c/busses/i2c-ast2600.c | 330 +++-- - drivers/irqchip/Makefile | 1 + - drivers/irqchip/irq-aspeed-intc.c | 4 +- - drivers/irqchip/irq-ast2700-intc0.c | 509 +++++++ - drivers/irqchip/irq-ast2700-intc1.c | 254 ++++ - drivers/pci/controller/Kconfig | 17 +- - drivers/pci/controller/pcie-aspeed.c | 15 +- - drivers/phy/aspeed/Makefile | 2 +- - .../{aspeed-sgmii.c => phy-aspeed-sgmii.c} | 194 +-- - drivers/soc/aspeed/Kconfig | 36 +- - drivers/soc/aspeed/Makefile | 5 +- - drivers/soc/aspeed/aspeed-bmc-dev.c | 48 +- - drivers/soc/aspeed/aspeed-lpc-pcc.c | 33 +- - drivers/soc/aspeed/aspeed-mbox.c | 2 +- - drivers/soc/aspeed/aspeed-mctp.c | 16 +- - drivers/soc/aspeed/aspeed-pcie-mmbi.c | 3 +- - drivers/soc/aspeed/aspeed-udma.c | 38 +- - drivers/soc/aspeed/espi/Kconfig | 18 + - drivers/soc/aspeed/espi/Makefile | 6 + - .../soc/aspeed/{ => espi}/aspeed-espi-comm.h | 101 +- - drivers/soc/aspeed/espi/aspeed-espi.c | 256 ++++ - drivers/soc/aspeed/espi/aspeed-espi.h | 227 +++ - drivers/soc/aspeed/{ => espi}/ast2500-espi.c | 483 ++----- - drivers/soc/aspeed/{ => espi}/ast2500-espi.h | 24 +- - drivers/soc/aspeed/{ => espi}/ast2600-espi.c | 670 +++------ - drivers/soc/aspeed/{ => espi}/ast2600-espi.h | 33 +- - drivers/soc/aspeed/{ => espi}/ast2700-espi.c | 848 +++++------ - drivers/soc/aspeed/{ => espi}/ast2700-espi.h | 29 +- - .../aspeed/{ => espi}/ast2700-rtc-over-espi.c | 0 - drivers/soc/aspeed/rvas/video_main.c | 14 +- - drivers/tty/serial/8250/8250_aspeed.c | 261 ++-- - include/linux/soc/aspeed/aspeed-udma.h | 8 +- - 70 files changed, 8968 insertions(+), 2185 deletions(-) - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts - create mode 100644 arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts - create mode 100644 crypto/aspeed_crypt.c - create mode 100644 drivers/bus/aspeed-ltpi.h - create mode 100644 drivers/irqchip/irq-ast2700-intc0.c - create mode 100644 drivers/irqchip/irq-ast2700-intc1.c - rename drivers/phy/aspeed/{aspeed-sgmii.c => phy-aspeed-sgmii.c} (50%) - create mode 100644 drivers/soc/aspeed/espi/Kconfig - create mode 100644 drivers/soc/aspeed/espi/Makefile - rename drivers/soc/aspeed/{ => espi}/aspeed-espi-comm.h (83%) - create mode 100644 drivers/soc/aspeed/espi/aspeed-espi.c - create mode 100644 drivers/soc/aspeed/espi/aspeed-espi.h - rename drivers/soc/aspeed/{ => espi}/ast2500-espi.c (77%) - rename drivers/soc/aspeed/{ => espi}/ast2500-espi.h (91%) - rename drivers/soc/aspeed/{ => espi}/ast2600-espi.c (75%) - rename drivers/soc/aspeed/{ => espi}/ast2600-espi.h (91%) - rename drivers/soc/aspeed/{ => espi}/ast2700-espi.c (76%) - rename drivers/soc/aspeed/{ => espi}/ast2700-espi.h (89%) - rename drivers/soc/aspeed/{ => espi}/ast2700-rtc-over-espi.c (100%) - -diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms -index 30dad6548..492192617 100644 ---- a/arch/arm64/Kconfig.platforms -+++ b/arch/arm64/Kconfig.platforms -@@ -42,6 +42,7 @@ config ARCH_APPLE - - config ARCH_ASPEED - bool "Aspeed SoC family" -+ select AST2700_IRQ - help - Say yes if you intend to run on an Aspeed ast2700 or similar - seventh generation Aspeed BMCs. -diff --git a/arch/arm64/boot/dts/aspeed/Makefile b/arch/arm64/boot/dts/aspeed/Makefile -index 4458a1bfe..7c31f3159 100644 ---- a/arch/arm64/boot/dts/aspeed/Makefile -+++ b/arch/arm64/boot/dts/aspeed/Makefile -@@ -13,4 +13,15 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ - ast2700-evb-256-abr.dtb \ - ast2700-slt.dtb \ - ast2700-fpga.dtb \ -- ast2700-ci-host.dtb -+ ast2700-ci-host.dtb \ -+ ast2700a1-evb.dtb \ -+ ast2700a1-raw.dtb \ -+ ast2700a1-ncsi.dtb \ -+ ast2700a1-dcscm.dtb \ -+ ast2700a1-dcscm_ast1700a1-evb.dtb \ -+ ast2700a1-dcscm_ast1700a1-evb-dual.dtb \ -+ ast2700a1-dcscm_ast1800-evb.dtb \ -+ ast2700a1-evb-256-abr.dtb \ -+ ast2700a1-evb-s0.dtb \ -+ ast2700a1-evb-s1.dtb \ -+ ast2700a1-ci-host.dtb -diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi -index df3a1d7a2..c7cdd2b2f 100644 ---- a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi -+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi -@@ -249,6 +249,7 @@ vhuba1: usb-vhub@12011000 { - pinctrl-0 = <&pinctrl_usb2axhpd1_default>; - aspeed,device = <&pcie_cfg0>; - aspeed,scu = <&syscon0>; -+ aspeed,enlarge-fifo; - status = "disabled"; - }; - -@@ -282,6 +283,7 @@ vhubb1: usb-vhub@12021000 { - pinctrl-0 = <&pinctrl_usb2bxhpd1_default>; - aspeed,device = <&pcie_cfg1>; - aspeed,scu = <&syscon0>; -+ aspeed,enlarge-fifo; - status = "disabled"; - }; - -@@ -540,8 +542,7 @@ pcie0: pcie@120e0000 { - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x00 0xff>; -- ranges = <0x01000000 0x0 0x00000000 0x0 0x00000000 0x0 0x00008000>, /* I/O */ -- <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; /* memory */ -+ ranges = <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; - interrupts = ; - resets = <&syscon0 SCU0_RESET_H2X0>, - <&syscon0 SCU0_RESET_PCIE0RST>; -@@ -578,8 +579,7 @@ pcie1: pcie@120f0000 { - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x00 0xff>; -- ranges = <0x01000000 0 0x00000000 0x0 0x00000000 0x0 0x00008000>, -- <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x20000000>; /* memory */ -+ ranges = <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x20000000>; - interrupts = ; - resets = <&syscon0 SCU0_RESET_H2X1>, - <&syscon0 SCU0_RESET_PCIE1RST>; -@@ -696,18 +696,18 @@ silicon-id@0 { - }; - - scu_ic0: interrupt-controller@1D0 { -- #interrupt-cells = <1>; - compatible = "aspeed,ast2700-scu-ic0"; - reg = <0x1d0 0xc>; - interrupts = ; -+ #interrupt-cells = <1>; - interrupt-controller; - }; - - scu_ic1: interrupt-controller@1E0 { -- #interrupt-cells = <1>; - compatible = "aspeed,ast2700-scu-ic1"; - reg = <0x1e0 0xc>; - interrupts = ; -+ #interrupt-cells = <1>; - interrupt-controller; - }; - -@@ -789,6 +789,7 @@ gfx: display@12c09000 { - clocks = <&syscon0 SCU0_CLK_GATE_CRT0CLK>; - resets = <&syscon0 SCU0_RESET_CRT0>; - syscon = <&syscon0>; -+ syscon_io = <&syscon1>; - status = "disabled"; - interrupts-extended = <&gic GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, - <&scu_ic0 ASPEED_AST2700_SCU_IC0_PCIE_PERST_LO_TO_HI>, -@@ -835,6 +836,8 @@ pcie_phy1: phy@12c15800 { - pcie_vuart0: serial@12c18000 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x12c18000 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts = ; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -@@ -844,6 +847,8 @@ pcie_vuart0: serial@12c18000 { - pcie_vuart1: serial@12c18100 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x12c18100 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts = ; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -@@ -853,6 +858,8 @@ pcie_vuart1: serial@12c18100 { - pcie_vuart2: serial@12c18200 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x12c18200 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts = ; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -@@ -862,6 +869,8 @@ pcie_vuart2: serial@12c18200 { - pcie_vuart3: serial@12c18300 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x12c18300 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts = ; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -@@ -1295,18 +1304,6 @@ mdio2: mdio@14040010 { - status = "disabled"; - }; - -- sgmii: phy@14C01000 { -- compatible = "aspeed,ast2700-sgmii"; -- reg = <0x0 0x14c01000 0x0 0x40>; -- -- aspeed,plda = <&pcie_phy2>; -- -- pinctrl-names = "default"; -- pinctrl-0 = <&pinctrl_sgmii_default>; -- #phy-cells = <0>; -- status = "disabled"; -- }; -- - mac0: ethernet@14050000 { - compatible = "aspeed,ast2700-mac", "faraday,ftgmac100"; - reg = <0x0 0x14050000 0x0 0x200>; -@@ -1315,6 +1312,8 @@ mac0: ethernet@14050000 { - clocks = <&syscon1 SCU1_CLK_GATE_MAC0CLK>; - resets = <&syscon1 SCU1_RESET_MAC0>; - status = "disabled"; -+ -+ aspeed,scu = <&syscon1>; - }; - - mac1: ethernet@14060000 { -@@ -1325,6 +1324,8 @@ mac1: ethernet@14060000 { - clocks = <&syscon1 SCU1_CLK_GATE_MAC1CLK>; - resets = <&syscon1 SCU1_RESET_MAC1>; - status = "disabled"; -+ -+ aspeed,scu = <&syscon1>; - }; - - mac2: ethernet@14070000 { -@@ -1338,6 +1339,8 @@ mac2: ethernet@14070000 { - clocks = <&syscon1 SCU1_CLK_GATE_MAC2CLK>; - resets = <&syscon1 SCU1_RESET_MAC2>; - status = "disabled"; -+ -+ aspeed,scu = <&syscon1>; - }; - - sdio_controller: sdc@14080000 { -@@ -1379,8 +1382,7 @@ pcie2: pcie@140d0000 { - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x00 0xff>; -- ranges = <0x01000000 0 0x00000000 0x0 0x00000000 0x0 0x00008000>, -- <0x02000000 0 0xa0000000 0x0 0xa0000000 0x0 0x20000000>; /* memory */ -+ ranges = <0x02000000 0 0xa0000000 0x0 0xa0000000 0x0 0x20000000>; - interrupts-extended = <&intc1_4 31>; - resets = <&syscon1 SCU1_RESET_H2X>, - <&syscon1 SCU1_RESET_PCIE2RST>; -@@ -1503,6 +1505,19 @@ adc1: adc@14c00100 { - status = "disabled"; - }; - -+ sgmii: phy@14c01000 { -+ compatible = "aspeed,ast2700-sgmii"; -+ reg = <0x0 0x14c01000 0x0 0x40>; -+ -+ phys = <&pcie_phy2>; -+ aspeed,scu = <&syscon1>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_sgmii_default>; -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ - syscon1: syscon@14c02000 { - compatible = "aspeed,ast2700-scu1", "syscon", "simple-mfd"; - reg = <0x0 0x14c02000 0x0 0x1000>; -@@ -1512,19 +1527,24 @@ syscon1: syscon@14c02000 { - #clock-cells = <1>; - #reset-cells = <1>; - -+ assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -+ <&syscon1 SCU1_CLK_RGMII>, -+ <&syscon1 SCU1_CLK_RMII>; -+ assigned-clock-rates = <200000000>, <125000000>, <50000000>; -+ - scu_ic2: interrupt-controller@100 { -- #interrupt-cells = <1>; - compatible = "aspeed,ast2700-scu-ic2"; - reg = <0x100 0x8>; - interrupts-extended = <&intc1_5 0>; -+ #interrupt-cells = <1>; - interrupt-controller; - }; - - scu_ic3: interrupt-controller@108 { -- #interrupt-cells = <1>; - compatible = "aspeed,ast2700-scu-ic3"; - reg = <0x108 0x8>; - interrupts-extended = <&intc1_5 26>; -+ #interrupt-cells = <1>; - interrupt-controller; - }; - -@@ -1778,6 +1798,7 @@ mctp2: mctp2@14c1a000 { - pcie_phy2: phy@14c1c000 { - compatible = "aspeed,ast2700-pcie-phy", "syscon"; - reg = <0x0 0x14c1c000 0x0 0x800>; -+ #phy-cells = <0>; - }; - - e2m_config2: e2m-config@14c1d000 { -@@ -2082,36 +2103,48 @@ i3c15: i3c15@14c2f000 { - vuart0: serial@14c30000 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x14c30000 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts-extended = <&intc1_0 17>; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -+ dma-channel = <12>; - status = "disabled"; - }; - - vuart1: serial@14c30100 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x14c30100 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts-extended = <&intc1_0 18>; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -+ dma-channel = <13>; - status = "disabled"; - }; - - vuart2: serial@14c30200 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x14c30200 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts-extended = <&intc1_1 17>; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -+ dma-channel = <14>; - status = "disabled"; - }; - - vuart3: serial@14c30300 { - compatible = "aspeed,ast2700-uart"; - reg = <0x0 0x14c30300 0x0 0x40>; -+ reg-shift = <2>; -+ reg-io-width = <4>; - interrupts-extended = <&intc1_1 18>; - clocks = <&syscon0 SCU0_CLK_APB>; - virtual; -+ dma-channel = <15>; - status = "disabled"; - }; - -@@ -2282,6 +2315,7 @@ uart0: serial@14c33000 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd0_default &pinctrl_rxd0_default>; -+ dma-channel = <0>; - status = "disabled"; - }; - -@@ -2296,6 +2330,7 @@ uart1: serial@14c33100 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>; -+ dma-channel = <1>; - status = "disabled"; - }; - -@@ -2310,6 +2345,7 @@ uart2: serial@14c33200 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>; -+ dma-channel = <2>; - status = "disabled"; - }; - -@@ -2324,6 +2360,7 @@ uart3: serial@14c33300 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd3_default &pinctrl_rxd3_default>; -+ dma-channel = <3>; - status = "disabled"; - }; - -@@ -2338,6 +2375,7 @@ uart5: serial@14c33400 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd5_default &pinctrl_rxd5_default>; -+ dma-channel = <4>; - status = "disabled"; - }; - -@@ -2352,6 +2390,7 @@ uart6: serial@14c33500 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd6_default &pinctrl_rxd6_default>; -+ dma-channel = <5>; - status = "disabled"; - }; - -@@ -2366,6 +2405,7 @@ uart7: serial@14c33600 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd7_default &pinctrl_rxd7_default>; -+ dma-channel = <6>; - status = "disabled"; - }; - -@@ -2380,6 +2420,7 @@ uart8: serial@14c33700 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd8_default &pinctrl_rxd8_default>; -+ dma-channel = <7>; - status = "disabled"; - }; - -@@ -2393,6 +2434,7 @@ uart9: serial@14c33800 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd9_default &pinctrl_rxd9_default>; -+ dma-channel = <8>; - status = "disabled"; - }; - -@@ -2406,6 +2448,7 @@ uart10: serial@14c33900 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd10_default &pinctrl_rxd10_default>; -+ dma-channel = <9>; - status = "disabled"; - }; - -@@ -2419,6 +2462,7 @@ uart11: serial@14c33a00 { - no-loopback-test; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_txd11_default &pinctrl_rxd11_default>; -+ dma-channel = <10>; - status = "disabled"; - }; - -@@ -2431,6 +2475,7 @@ uart12: serial@14c33b00 { - interrupts-extended = <&intc1_4 18>; - no-loopback-test; - pinctrl-names = "default"; -+ dma-channel = <11>; - status = "disabled"; - }; - -@@ -2460,10 +2505,14 @@ uart14: serial@14c33d00 { - - ltpi0: ltpi@14c34000 { - compatible = "aspeed-ltpi"; -- reg = <0x0 0x14c34000 0x0 0x100>; -+ reg = <0x0 0x14c34000 0x0 0x100>, -+ <0x0 0x14c34200 0x0 0x100>, -+ <0x0 0x14c34800 0x0 0x100>; -+ reg-names = "base", "phy", "top"; - clocks = <&syscon1 SCU1_CLK_GATE_LTPICLK>, - <&syscon1 SCU1_CLK_GATE_LTPIPHYCLK>; - clock-names = "ahb", "phy"; -+ aspeed,scu = <&syscon1>; - resets = <&syscon1 SCU1_RESET_LTPI0>; - interrupts-extended = <&intc1_5 12>; - status = "disabled"; -@@ -2483,10 +2532,14 @@ ltpi0_gpio: ltpi0-gpio@14c34c00 { - - ltpi1: ltpi@14c35000 { - compatible = "aspeed-ltpi"; -- reg = <0x0 0x14c35000 0x0 0x100>; -+ reg = <0x0 0x14c35000 0x0 0x100>, -+ <0x0 0x14c35200 0x0 0x100>, -+ <0x0 0x14c35800 0x0 0x100>; -+ reg-names = "base", "phy", "top"; - clocks = <&syscon1 SCU1_CLK_GATE_LTPICLK>, - <&syscon1 SCU1_CLK_GATE_LTPI1TXCLK>; - clock-names = "ahb", "phy"; -+ aspeed,scu = <&syscon1>; - resets = <&syscon1 SCU1_RESET_LTPI1>; - interrupts-extended = <&intc1_5 13>; - status = "disabled"; -@@ -2566,7 +2619,7 @@ fsim1: fsi@23800000 { - reg = <0x0 0x23800000 0x0 0x94>; - interrupts-extended = <&intc1_5 7>; - pinctrl-names = "default"; -- pinctrl-0 = <&pinctrl_fsi1_default>; -+ pinctrl-0 = <&pinctrl_fsi2_default>; - clocks = <&syscon1 SCU1_CLK_GATE_FSICLK>; - resets = <&syscon1 SCU1_RESET_FSI>; - status = "disabled"; -@@ -2600,7 +2653,7 @@ i2c_global: i2c-global-regs@0 { - i2c0: i2c-bus@100 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x100 0x80>, <0x1A0 0x20>; -+ reg = <0x100 0xA0>, <0x1C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2617,7 +2670,7 @@ i2c0: i2c-bus@100 { - i2c1: i2c-bus@200 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x200 0x80>, <0x2A0 0x20>; -+ reg = <0x200 0xA0>, <0x2C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2634,7 +2687,7 @@ i2c1: i2c-bus@200 { - i2c2: i2c-bus@300 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x300 0x80>, <0x3A0 0x20>; -+ reg = <0x300 0xA0>, <0x3C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2651,7 +2704,7 @@ i2c2: i2c-bus@300 { - i2c3: i2c-bus@400 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x400 0x80>, <0x4A0 0x20>; -+ reg = <0x400 0xA0>, <0x4C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - clocks = <&syscon1 SCU1_CLK_APB>; -@@ -2667,7 +2720,7 @@ i2c3: i2c-bus@400 { - i2c4: i2c-bus@500 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x500 0x80>, <0x5A0 0x20>; -+ reg = <0x500 0xA0>, <0x5C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2684,7 +2737,7 @@ i2c4: i2c-bus@500 { - i2c5: i2c-bus@600 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x600 0x80>, <0x6A0 0x20>; -+ reg = <0x600 0xA0>, <0x6C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2701,7 +2754,7 @@ i2c5: i2c-bus@600 { - i2c6: i2c-bus@700 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x700 0x80>, <0x7A0 0x20>; -+ reg = <0x700 0xA0>, <0x7C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2718,7 +2771,7 @@ i2c6: i2c-bus@700 { - i2c7: i2c-bus@800 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x800 0x80>, <0x8A0 0x20>; -+ reg = <0x800 0xA0>, <0x8C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2735,7 +2788,7 @@ i2c7: i2c-bus@800 { - i2c8: i2c-bus@900 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x900 0x80>, <0x9A0 0x20>; -+ reg = <0x900 0xA0>, <0x9C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2752,7 +2805,7 @@ i2c8: i2c-bus@900 { - i2c9: i2c-bus@a00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xA00 0x80>, <0xAA0 0x20>; -+ reg = <0xA00 0xA0>, <0xAC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2769,7 +2822,7 @@ i2c9: i2c-bus@a00 { - i2c10: i2c-bus@b00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xB00 0x80>, <0xBA0 0x20>; -+ reg = <0xB00 0xA0>, <0xBC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2786,7 +2839,7 @@ i2c10: i2c-bus@b00 { - i2c11: i2c-bus@c00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xC00 0x80>, <0xCA0 0x20>; -+ reg = <0xC00 0xA0>, <0xCC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2803,7 +2856,7 @@ i2c11: i2c-bus@c00 { - i2c12: i2c-bus@d00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xD00 0x80>, <0xDA0 0x20>; -+ reg = <0xD00 0xA0>, <0xDC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2820,7 +2873,7 @@ i2c12: i2c-bus@d00 { - i2c13: i2c-bus@e00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xE00 0x80>, <0xEA0 0x20>; -+ reg = <0xE00 0xA0>, <0xEC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2837,7 +2890,7 @@ i2c13: i2c-bus@e00 { - i2c14: i2c-bus@f00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xF00 0x80>, <0xFA0 0x20>; -+ reg = <0xF00 0xA0>, <0xFC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -@@ -2854,7 +2907,7 @@ i2c14: i2c-bus@f00 { - i2c15: i2c-bus@1000 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x1000 0x80>, <0x10A0 0x20>; -+ reg = <0x1000 0xA0>, <0x10C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <&i2c_global>; - aspeed,enable-dma; -diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi -index d5657392d..ee4c46b64 100644 ---- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi -@@ -388,7 +388,7 @@ ltpi0_i2c_global: i2c-global-regs@0 { - ltpi0_i2c0: i2c-bus@100 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x100 0x80>, <0x1a0 0x20>; -+ reg = <0x100 0xA0>, <0x1C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -405,7 +405,7 @@ ltpi0_i2c0: i2c-bus@100 { - ltpi0_i2c1: i2c-bus@200 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x200 0x80>, <0x2a0 0x20>; -+ reg = <0x200 0xA0>, <0x2C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -422,7 +422,7 @@ ltpi0_i2c1: i2c-bus@200 { - ltpi0_i2c2: i2c-bus@300 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x300 0x80>, <0x3a0 0x20>; -+ reg = <0x300 0xA0>, <0x3C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -439,7 +439,7 @@ ltpi0_i2c2: i2c-bus@300 { - ltpi0_i2c3: i2c-bus@400 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x400 0x80>, <0x4a0 0x20>; -+ reg = <0x400 0xA0>, <0x4C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -456,7 +456,7 @@ ltpi0_i2c3: i2c-bus@400 { - ltpi0_i2c4: i2c-bus@500 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x500 0x80>, <0x5a0 0x20>; -+ reg = <0x500 0xA0>, <0x5C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -473,7 +473,7 @@ ltpi0_i2c4: i2c-bus@500 { - ltpi0_i2c5: i2c-bus@600 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x600 0x80>, <0x6a0 0x20>; -+ reg = <0x600 0xA0>, <0x6C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -490,7 +490,7 @@ ltpi0_i2c5: i2c-bus@600 { - ltpi0_i2c6: i2c-bus@700 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x700 0x80>, <0x7a0 0x20>; -+ reg = <0x700 0xA0>, <0x7C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -507,7 +507,7 @@ ltpi0_i2c6: i2c-bus@700 { - ltpi0_i2c7: i2c-bus@800 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x800 0x80>, <0x8a0 0x20>; -+ reg = <0x800 0xA0>, <0x8C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -524,7 +524,7 @@ ltpi0_i2c7: i2c-bus@800 { - ltpi0_i2c8: i2c-bus@900 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x900 0x80>, <0x9a0 0x20>; -+ reg = <0x900 0xA0>, <0x9C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -541,7 +541,7 @@ ltpi0_i2c8: i2c-bus@900 { - ltpi0_i2c9: i2c-bus@a00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xa00 0x80>, <0xaa0 0x20>; -+ reg = <0xA00 0xA0>, <0xAC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -558,7 +558,7 @@ ltpi0_i2c9: i2c-bus@a00 { - ltpi0_i2c10: i2c-bus@b00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xb00 0x80>, <0xba0 0x20>; -+ reg = <0xB00 0xA0>, <0xBC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -575,7 +575,7 @@ ltpi0_i2c10: i2c-bus@b00 { - ltpi0_i2c11: i2c-bus@c00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xc00 0x80>, <0xca0 0x20>; -+ reg = <0xC00 0xA0>, <0xCC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -592,7 +592,7 @@ ltpi0_i2c11: i2c-bus@c00 { - ltpi0_i2c12: i2c-bus@d00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xd00 0x80>, <0xda0 0x20>; -+ reg = <0xD00 0xA0>, <0xDC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -609,7 +609,7 @@ ltpi0_i2c12: i2c-bus@d00 { - ltpi0_i2c13: i2c-bus@e00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xe00 0x80>, <0xea0 0x20>; -+ reg = <0xE00 0xA0>, <0xEC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -626,7 +626,7 @@ ltpi0_i2c13: i2c-bus@e00 { - ltpi0_i2c14: i2c-bus@f00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xf00 0x80>, <0xfa0 0x20>; -+ reg = <0xF00 0xA0>, <0xFC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -643,7 +643,7 @@ ltpi0_i2c14: i2c-bus@f00 { - ltpi0_i2c15: i2c-bus@1000 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x1000 0x80>, <0x10a0 0x20>; -+ reg = <0x1000 0xA0>, <0x10C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi -index bb0a148e0..0406085a5 100644 ---- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi -@@ -388,7 +388,7 @@ ltpi1_i2c_global: i2c-global-regs@0 { - ltpi1_i2c0: i2c-bus@100 { - #address-cells = <1>; - #size-cells = <1>; -- reg = <0x100 0x80>, <0x1a0 0x20>; -+ reg = <0x100 0xA0>, <0x1C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -405,7 +405,7 @@ ltpi1_i2c0: i2c-bus@100 { - ltpi1_i2c1: i2c-bus@200 { - #address-cells = <1>; - #size-cells = <1>; -- reg = <0x200 0x80>, <0x2a0 0x20>; -+ reg = <0x200 0xA0>, <0x2C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -422,7 +422,7 @@ ltpi1_i2c1: i2c-bus@200 { - ltpi1_i2c2: i2c-bus@300 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x300 0x80>, <0x3a0 0x20>; -+ reg = <0x300 0xA0>, <0x3C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -439,7 +439,7 @@ ltpi1_i2c2: i2c-bus@300 { - ltpi1_i2c3: i2c-bus@400 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x400 0x80>, <0x4a0 0x20>; -+ reg = <0x400 0xA0>, <0x4C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -456,7 +456,7 @@ ltpi1_i2c3: i2c-bus@400 { - ltpi1_i2c4: i2c-bus@500 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x500 0x80>, <0x5a0 0x20>; -+ reg = <0x500 0xA0>, <0x5C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -473,7 +473,7 @@ ltpi1_i2c4: i2c-bus@500 { - ltpi1_i2c5: i2c-bus@600 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x600 0x80>, <0x6a0 0x20>; -+ reg = <0x600 0xA0>, <0x6C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -490,7 +490,7 @@ ltpi1_i2c5: i2c-bus@600 { - ltpi1_i2c6: i2c-bus@700 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x700 0x80>, <0x7a0 0x20>; -+ reg = <0x700 0xA0>, <0x7C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -507,7 +507,7 @@ ltpi1_i2c6: i2c-bus@700 { - ltpi1_i2c7: i2c-bus@800 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x800 0x80>, <0x8a0 0x20>; -+ reg = <0x800 0xA0>, <0x8C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -524,7 +524,7 @@ ltpi1_i2c7: i2c-bus@800 { - ltpi1_i2c8: i2c-bus@900 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x900 0x80>, <0x9a0 0x20>; -+ reg = <0x900 0xA0>, <0x9C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -541,7 +541,7 @@ ltpi1_i2c8: i2c-bus@900 { - ltpi1_i2c9: i2c-bus@a00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xa00 0x80>, <0xaa0 0x20>; -+ reg = <0xA00 0xA0>, <0xAC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -558,7 +558,7 @@ ltpi1_i2c9: i2c-bus@a00 { - ltpi1_i2c10: i2c-bus@b00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xb00 0x80>, <0xba0 0x20>; -+ reg = <0xB00 0xA0>, <0xBC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -575,7 +575,7 @@ ltpi1_i2c10: i2c-bus@b00 { - ltpi1_i2c11: i2c-bus@c00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xc00 0x80>, <0xca0 0x20>; -+ reg = <0xC00 0xA0>, <0xCC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -592,7 +592,7 @@ ltpi1_i2c11: i2c-bus@c00 { - ltpi1_i2c12: i2c-bus@d00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xd00 0x80>, <0xda0 0x20>; -+ reg = <0xD00 0xA0>, <0xDC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -609,7 +609,7 @@ ltpi1_i2c12: i2c-bus@d00 { - ltpi1_i2c13: i2c-bus@e00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xe00 0x80>, <0xea0 0x20>; -+ reg = <0xE00 0xA0>, <0xEC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -626,7 +626,7 @@ ltpi1_i2c13: i2c-bus@e00 { - ltpi1_i2c14: i2c-bus@f00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xf00 0x80>, <0xfa0 0x20>; -+ reg = <0xF00 0xA0>, <0xFC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -@@ -643,7 +643,7 @@ ltpi1_i2c14: i2c-bus@f00 { - ltpi1_i2c15: i2c-bus@1000 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x1000 0x80>, <0x10a0 0x20>; -+ reg = <0x1000 0xA0>, <0x10C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi1_i2c_global>; - aspeed,enable-dma; -diff --git a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi -index e3857cd71..cbc8da221 100644 ---- a/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi -+++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi -@@ -376,7 +376,7 @@ ltpi0_i2c_global: i2c-global-regs@0 { - ltpi0_i2c0: i2c-bus@100 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x100 0x80>, <0x1a0 0x20>; -+ reg = <0x100 0xA0>, <0x1C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -393,7 +393,7 @@ ltpi0_i2c0: i2c-bus@100 { - ltpi0_i2c1: i2c-bus@200 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x200 0x80>, <0x2a0 0x20>; -+ reg = <0x200 0xA0>, <0x2C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -410,7 +410,7 @@ ltpi0_i2c1: i2c-bus@200 { - ltpi0_i2c2: i2c-bus@300 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x300 0x80>, <0x3a0 0x20>; -+ reg = <0x300 0xA0>, <0x3C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -427,7 +427,7 @@ ltpi0_i2c2: i2c-bus@300 { - ltpi0_i2c3: i2c-bus@400 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x400 0x80>, <0x4a0 0x20>; -+ reg = <0x400 0xA0>, <0x4C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -444,7 +444,7 @@ ltpi0_i2c3: i2c-bus@400 { - ltpi0_i2c4: i2c-bus@500 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x500 0x80>, <0x5a0 0x20>; -+ reg = <0x500 0xA0>, <0x5C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -461,7 +461,7 @@ ltpi0_i2c4: i2c-bus@500 { - ltpi0_i2c5: i2c-bus@600 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x600 0x80>, <0x6a0 0x20>; -+ reg = <0x600 0xA0>, <0x6C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -478,7 +478,7 @@ ltpi0_i2c5: i2c-bus@600 { - ltpi0_i2c6: i2c-bus@700 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x700 0x80>, <0x7a0 0x20>; -+ reg = <0x700 0xA0>, <0x7C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -495,7 +495,7 @@ ltpi0_i2c6: i2c-bus@700 { - ltpi0_i2c7: i2c-bus@800 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x800 0x80>, <0x8a0 0x20>; -+ reg = <0x800 0xA0>, <0x8C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -512,7 +512,7 @@ ltpi0_i2c7: i2c-bus@800 { - ltpi0_i2c8: i2c-bus@900 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x900 0x80>, <0x9a0 0x20>; -+ reg = <0x900 0xA0>, <0x9C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -529,7 +529,7 @@ ltpi0_i2c8: i2c-bus@900 { - ltpi0_i2c9: i2c-bus@a00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xa00 0x80>, <0xaa0 0x20>; -+ reg = <0xA00 0xA0>, <0xAC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -546,7 +546,7 @@ ltpi0_i2c9: i2c-bus@a00 { - ltpi0_i2c10: i2c-bus@b00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xb00 0x80>, <0xba0 0x20>; -+ reg = <0xB00 0xA0>, <0xBC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -563,7 +563,7 @@ ltpi0_i2c10: i2c-bus@b00 { - ltpi0_i2c11: i2c-bus@c00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xc00 0x80>, <0xca0 0x20>; -+ reg = <0xC00 0xA0>, <0xCC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -580,7 +580,7 @@ ltpi0_i2c11: i2c-bus@c00 { - ltpi0_i2c12: i2c-bus@d00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xd00 0x80>, <0xda0 0x20>; -+ reg = <0xD00 0xA0>, <0xDC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -597,7 +597,7 @@ ltpi0_i2c12: i2c-bus@d00 { - ltpi0_i2c13: i2c-bus@e00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xe00 0x80>, <0xea0 0x20>; -+ reg = <0xE00 0xA0>, <0xEC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -614,7 +614,7 @@ ltpi0_i2c13: i2c-bus@e00 { - ltpi0_i2c14: i2c-bus@f00 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0xf00 0x80>, <0xfa0 0x20>; -+ reg = <0xF00 0xA0>, <0xFC0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -@@ -631,7 +631,7 @@ ltpi0_i2c14: i2c-bus@f00 { - ltpi0_i2c15: i2c-bus@1000 { - #address-cells = <1>; - #size-cells = <0>; -- reg = <0x1000 0x80>, <0x10a0 0x20>; -+ reg = <0x1000 0xA0>, <0x10C0 0x40>; - compatible = "aspeed,ast2700-i2c"; - aspeed,global-regs = <<pi0_i2c_global>; - aspeed,enable-dma; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts b/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts -index 4ed9dbefe..1a2a57cf3 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts -@@ -95,3 +95,33 @@ &pcie1_mmbi4 { - &pcie1 { - status = "okay"; - }; -+ -+&mdio0 { -+ status = "disabled"; -+}; -+ -+&mac0 { -+ status = "disabled"; -+}; -+ -+&mdio2 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&sgmii { -+ status = "okay"; -+}; -+ -+&mac2 { -+ status = "okay"; -+ -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts -index 952d080d7..551fa77b6 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts -@@ -493,13 +493,6 @@ &mac0 { - pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; - }; - --&syscon1 { -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; --}; -- - &jtag1 { - status = "okay"; - }; -@@ -589,6 +582,7 @@ &espi0 { - perif-mcyc-enable; - perif-mcyc-src-addr = <0x0 0x98000000>; - perif-mcyc-size = <0x0 0x10000>; -+ vw-pltrst-monitor; - oob-dma-mode; - flash-dma-mode; - }; -@@ -604,6 +598,7 @@ &espi1 { - perif-mcyc-enable; - perif-mcyc-src-addr = <0x0 0x98000000>; - perif-mcyc-size = <0x0 0x10000>; -+ vw-pltrst-monitor; - oob-dma-mode; - flash-dma-mode; - }; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts -index 3f356a8d9..3262e90bf 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts -@@ -433,10 +433,6 @@ &syscon1 { - mac1-clk-delay = <0 0 - 0 0 - 0 0>; -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; - }; - - &vhuba0 { -@@ -463,3 +459,23 @@ &vhubb0 { - &vhubb1 { - status = "disabled"; - }; -+ -+&vhubc { -+ status = "disabled"; -+}; -+ -+&vhubd { -+ status = "okay"; -+}; -+ -+&ehci2 { -+ status = "okay"; -+}; -+ -+&ehci3 { -+ status = "disabled"; -+}; -+ -+&pcie2 { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts -index 4b34c6aef..be59bdb7c 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts -@@ -9,7 +9,6 @@ - #define DUAL_NODE 0 // 1: DUAL_NODE, 0: SINGLE_NODE - #define PCIE0_EP 1 // 1: EP, 0: RC - #define PCIE1_EP 1 // 1: EP, 0: RC --#define PCIE2_RC 1 // 1: RC, 0: SGMII - - / { - model = "AST2700 EVB"; -@@ -269,7 +268,8 @@ &adc1 { - pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default - &pinctrl_adc10_default &pinctrl_adc11_default - &pinctrl_adc12_default &pinctrl_adc13_default -- &pinctrl_adc14_default &pinctrl_adc15_default>; -+ &pinctrl_adc14_default &pinctrl_adc15_default -+ &pinctrl_adc13_bias>; - }; - - &pinctrl0 { -@@ -355,6 +355,10 @@ pinctrl_rgmii1_driving: rgmii1-driving { - "C18", "C6", "C7", "D7", "N13", "C8"; - drive-strength = <1>; - }; -+ pinctrl_adc13_bias: adc13-bias { -+ pins = "W14"; -+ bias-disable; -+ }; - }; - - &gpio1 { -@@ -682,6 +686,9 @@ &mac0 { - - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; -+ -+ rx-internal-delay-ps = <0>; -+ tx-internal-delay-ps = <0>; - }; - - &mac1 { -@@ -692,6 +699,9 @@ &mac1 { - - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_rgmii1_driving>; -+ -+ rx-internal-delay-ps = <0>; -+ tx-internal-delay-ps = <0>; - }; - - #if 0 // Default to disable RC & SGMII -@@ -725,13 +735,6 @@ &mac2 { - #endif - #endif - --&syscon1 { -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; --}; -- - &espi0 { - status = "okay"; - perif-dma-mode; -@@ -744,6 +747,7 @@ &espi0 { - perif-mcyc-size = <0x0 0x10000>; - memory-region = <&espi0_mcyc_memory>; - perif-rtc-enable; -+ vw-pltrst-monitor; - oob-dma-mode; - flash-dma-mode; - #if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten -@@ -781,6 +785,7 @@ &espi1 { - perif-mcyc-src-addr = <0x0 0x98000000>; - perif-mcyc-size = <0x0 0x10000>; - perif-rtc-enable; -+ vw-pltrst-monitor; - oob-dma-mode; - flash-dma-mode; - #if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten -@@ -1171,7 +1176,6 @@ &ehci1 { - - &uhci0 { - status = "okay"; -- memory-region = <&uhci0_reserved>; - }; - - #endif -@@ -1206,16 +1210,14 @@ &usb3ahp { - pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; - }; - --&usb3bhp { -+&vhubb0 { - status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2bhpd0_default>; - }; - --&uphy2b { -- status = "okay"; --}; -- --&vhubb1 { -+&usb3bhp { - status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3bxhp_default &pinctrl_usb2bxhp_default>; - }; - - &vhubc { -@@ -1232,7 +1234,6 @@ &ehci3 { - - &uhci1 { - status = "okay"; -- memory-region = <&uhci1_reserved>; - }; - - &wdt0 { -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts -index e35822895..8e33d950b 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts -@@ -681,10 +681,6 @@ &syscon1 { - mac1-clk-delay = <0x31 0x31 - 0x10 0x10 - 0x10 0x10>; -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; - }; - - &espi0 { -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts b/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts -index e35822895..8e33d950b 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts -@@ -681,10 +681,6 @@ &syscon1 { - mac1-clk-delay = <0x31 0x31 - 0x10 0x10 - 0x10 0x10>; -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; - }; - - &espi0 { -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts b/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts -index e55578d4c..786b75435 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts -@@ -676,10 +676,6 @@ &syscon1 { - mac1-clk-delay = <0x18 0x17 - 0x10 0x10 - 0x10 0x10>; -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; - }; - - &espi0 { -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts b/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts -index 812aba3b5..3f213d834 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts -@@ -45,8 +45,4 @@ &syscon1 { - mac1-clk-delay = <0 0 - 0 0 - 0 0>; -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; - }; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi b/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi -index c8f99cd02..c09e51b0c 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi -+++ b/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi -@@ -26,6 +26,7 @@ espi0_mmbi_memory: espi0-mmbi-memory@424000000 { - - #if PCIE0_EP - bmc_dev0_memory: bmc-dev0-memory@423800000 { -+ compatible = "shared-dma-pool"; - reg = <0x4 0x23800000 0x0 0x100000>; - no-map; - }; -@@ -44,6 +45,7 @@ pcie0_mmbi0_memory: pcie0-mmbi0-memory@423a00000 { - - #if PCIE1_EP - bmc_dev1_memory: bmc-dev1-memory@423900000 { -+ compatible = "shared-dma-pool"; - reg = <0x4 0x23900000 0x0 0x100000>; - no-map; - }; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts b/arch/arm64/boot/dts/aspeed/ast2700-slt.dts -index b835f6156..1134079a6 100644 ---- a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts -+++ b/arch/arm64/boot/dts/aspeed/ast2700-slt.dts -@@ -565,19 +565,6 @@ &mac2 { - phy-handle = <ðphy2>; - }; - --&syscon1 { -- mac0-clk-delay = <0x1a 0x15 -- 0x10 0x10 -- 0x10 0x10>; -- mac1-clk-delay = <0x19 0x17 -- 0x10 0x10 -- 0x10 0x10>; -- assigned-clocks = <&syscon1 SCU1_CLK_MACHCLK>, -- <&syscon1 SCU1_CLK_RGMII>, -- <&syscon1 SCU1_CLK_RMII>; -- assigned-clock-rates = <200000000>, <125000000>, <50000000>; --}; -- - &lpc0_kcs0 { - status = "okay"; - kcs-io-addr = <0xca0>; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts -new file mode 100644 -index 000000000..9c80e958a ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-ci-host.dts -@@ -0,0 +1,127 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-evb.dts" -+ -+/ { -+ model = "AST2700A1-CI-HOST"; -+}; -+ -+&bmc_dev0 { -+ status = "disabled"; -+}; -+ -+&xdma0 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart0 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs0 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs2 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_ibt { -+ status = "disabled"; -+}; -+ -+&pcie0_mmbi0 { -+ status = "disabled"; -+}; -+ -+&pcie0 { -+ status = "okay"; -+}; -+ -+&bmc_dev1 { -+ status = "disabled"; -+}; -+ -+&xdma1 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart2 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs0 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs2 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_ibt { -+ status = "disabled"; -+}; -+ -+&pcie1_mmbi4 { -+ status = "disabled"; -+}; -+ -+&pcie1 { -+ status = "okay"; -+}; -+ -+&mdio0 { -+ status = "disabled"; -+}; -+ -+&mac0 { -+ status = "disabled"; -+}; -+ -+&mdio2 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&sgmii { -+ status = "okay"; -+}; -+ -+&mac2 { -+ status = "okay"; -+ -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts -new file mode 100644 -index 000000000..bb4e4659b ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm.dts -@@ -0,0 +1,974 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "aspeed-g7.dtsi" -+#include -+#include -+ -+#define PCIE0_EP 1 // 1: EP, 0: RC -+#define PCIE1_EP 1 // 1: EP, 0: RC -+ -+/ { -+ model = "AST2700A1-DCSCM"; -+ compatible = "aspeed,ast2700"; -+ -+ chosen { -+ stdout-path = "serial12:115200n8"; -+ }; -+ -+ memory@400000000 { -+ device_type = "memory"; -+ reg = <0x4 0x00000000 0x0 0x40000000>; -+ }; -+ -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ #include "ast2700-reserved-mem.dtsi" -+ -+ video_engine_memory0: video0 { -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+ video_engine_memory1: video1{ -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+#if 0 -+ gfx_memory: framebuffer { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+#endif -+ }; -+ -+ iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <&adc0 7>, <&adc1 7>; -+ }; -+}; -+ -+&pwm_tach { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_pwm9_default>; -+}; -+ -+&adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ aspeed,battery-sensing; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc7_default>; -+}; -+ -+&adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ aspeed,battery-sensing; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc15_default>; -+}; -+ -+&pinctrl1 { -+ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { -+ pins = "U25"; -+ power-source = <1800>; -+ }; -+ -+ pinctrl_i3c0_driving: i3c0-driving { -+ pins = "U25", "U26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c1_driving: i3c1-driving { -+ pins = "Y26", "AA24"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c2_driving: i3c2-driving { -+ pins = "R25", "AA26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c3_driving: i3c3-driving { -+ pins = "R26", "Y25"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_rgmii0_driving: rgmii0-driving { -+ pins = "C20", "C19", "A8", "R14", "A7", "P14", -+ "D20", "A6", "B6", "N14", "B7", "B8"; -+ drive-strength = <1>; -+ }; -+}; -+ -+&i3c0 { -+ /* BMC_HPM_I3C_I2C_14, If AST1060 I3C_BMC_PFR_SCM_SEL(GPION4)=0 and I3C_SCM_EN(GPION5)=0 */ -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c1 { -+ /* BMC_I2C_I3C1_SCL1 */ -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c2 { -+ /* BMC_I2C_I3C2_SCL2 */ -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c3 { -+ /* I3C_DBG_SCM */ -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+/* AST2700 i3c4 -> AST1060 i3c2 for MCTP over I3C. */ -+&i3c4 { -+ /* I3C_PFR_BMC */ -+ initial-role = "target"; -+ pid = <0x000007ec 0x06000000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c5 { -+ /* I3C_MNG_BMC_SCM */ -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c6 { -+ /* I3C_SPD_SCM */ -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+/* Enable UART2 and UART9 for obmc-console. */ -+&uart2 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&uart9 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+/* Enable UART7 and UART10 for obmc-console. */ -+&uart7 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&uart10 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+/* UART3, UART13 and UART14 will be tunnelded to LTPI UART channels. */ -+&uart3 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&uart13 { -+ status = "okay"; -+}; -+ -+&uart14 { -+ status = "okay"; -+}; -+ -+&uart12 { -+ status = "okay"; -+}; -+ -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "bmc"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ u-boot@0 { -+ reg = <0x0 0x400000>; // 4MB -+ label = "u-boot"; -+ }; -+ u-boot-env@400000 { -+ reg = <0x400000 0x20000>; // 128KB -+ label = "u-boot-env"; -+ }; -+ kernel@420000 { -+ reg = <0x420000 0x900000>; // 9MB -+ label = "kernel"; -+ }; -+ rofs@d20000 { -+ reg = <0xd20000 0x24a0000>; // 36.625MB -+ label = "rofs"; -+ }; -+ rwfs@31c0000 { -+ reg = <0x31c0000 0xE40000>; // 14.25MB -+ label = "rwfs"; -+ }; -+ pfm@4000000 { -+ reg = <0x4000000 0x20000>; // 128KB -+ label = "pfm"; -+ }; -+ reserved-1@4020000 { -+ reg = <0x4020000 0x200000>; // 128KB -+ label = "reserved-1"; -+ }; -+ rc-image@4220000 { -+ reg = <0x4220000 0x3de0000>; // 63360KB -+ label = "rc-image"; -+ }; -+ image-stg@8000000 { -+ reg = <0x8000000 0x3de0000>; // 63360KB -+ label = "img-stg"; -+ }; -+ pfr-stg@bde0000 { -+ reg = <0xbde0000 0x100000>; // 1024KB -+ label = "pfr-stg"; -+ }; -+ cpld-stg@bee0000 { -+ reg = <0xbee0000 0x400000>; // 4096KB -+ label = "cpld-stg"; -+ }; -+ afm-stg@c2e0000 { -+ reg = <0xc2e0000 0x20000>; // 128KB -+ label = "afm-stg"; -+ }; -+ afm-rc@c300000 { -+ reg = <0xc300000 0x20000>; // 128KB -+ label = "afm-rc"; -+ }; -+ reserved-2@c320000 { -+ reg = <0xc320000 0x3ce0000>; // 62336KB -+ label = "reserved-2"; -+ }; -+ }; -+ }; -+}; -+ -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:0"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <1>; -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ spi0_pch_bios@0 { -+ reg = <0x0 0x3fe0000>; -+ label = "spi0_pch_reserved"; -+ }; -+ spi0_pch_pfm@3fe0000 { -+ reg = <0x3fe0000 0x20000>; -+ label = "spi0_pch_pfm"; -+ }; -+ spi0_pch_stg@4000000 { -+ reg = <0x4000000 0x2000000>; -+ label = "spi0_pch_stg"; -+ }; -+ spi0_pch_rc@6000000 { -+ reg = <0x6000000 0x2000000>; -+ label = "spi0_pch_rc"; -+ }; -+ }; -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:1"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <1>; -+ }; -+}; -+ -+&spi1 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:0"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <1>; -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ spi1_pch_reserved@0 { -+ reg = <0x0 0x7f0000>; -+ label = "spi1_pch_reserved"; -+ }; -+ -+ spi1_pch_stg@7f0000 { -+ reg = <0x7f0000 0x1400000>; -+ label = "spi1_pch_stg"; -+ }; -+ -+ spi1_pch_rc@1bf0000 { -+ reg = <0x1bf0000 0x1400000>; -+ label = "spi1_pch_rc"; -+ }; -+ -+ spi1_pch_pfm@2ff0000 { -+ reg = <0x2ff0000 0x10000>; -+ label = "spi1_pch_pfm"; -+ }; -+ -+ spi1_pch_bios@3000000 { -+ reg = <0x3000000 0x1000000>; -+ label = "spi1_pch_bios"; -+ }; -+ }; -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:1"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <1>; -+ }; -+}; -+ -+<pi0 { -+ status = "okay"; -+}; -+ -+<pi1 { -+ /* Do not tunnel I2C10 to the HPM */ -+ i2c-tunneling = <0x2f>; -+ status = "okay"; -+}; -+ -+/* The LTPI GPIO table is defined in Chapter 6 of the AST2700 LTPI Design Guide v10.pdf. */ -+/* line 0:BMC_GPI0(LTPI0_INL16), 1:BMC_GPO0(LTPI0_ONL16), 2:BMC_GPI1(LTPI0_INL17), 3:BMC_GPO1(LTPI0_ONL17), etc... */ -+/* BMC_GPI[63:0] = LTPI0_INL[79:16], BMC_GPO[63:0] = LTPI0_ONL[79:16] */ -+/* BMC_GPI[71:64] = LTPI0_ILL[11:4], BMC_GPO[71:64] = LTPI0_OLL[11:4] */ -+/* BMC_GPI[111:72] = LTPI0_INL[127:88],BMC_GPO[111:72] = LTPI0_ONL[127:88] */ -+<pi0_gpio { -+ status = "okay"; -+ gpio-line-names = -+ /*00-07*/ "","","","","","","","", -+ /*08-15*/ "","","","","","","","", -+ /*16-23*/ "","FM_CPU_FBRK_DEBUG_N","","FM_BMC_TRUST_N","","FM_RST_BTN_OUT_CPU0_PLD_N_OE","","FM_PWR_BTN_OUT_CPU0_N", -+ /*24-31*/ "","FM_BMC_ONCTL_N","","","","","","", -+ /*32-39*/ "","BIOS_POST_CODE_LED_0","","BIOS_POST_CODE_LED_1","","BIOS_POST_CODE_LED_2","","BIOS_POST_CODE_LED_3", -+ /*40-47*/ "FP_ID_BTN_N","BIOS_POST_CODE_LED_4","FP_RST_BTN_N","BIOS_POST_CODE_LED_5","","BIOS_POST_CODE_LED_6","","BIOS_POST_CODE_LED_7", -+ /*48-55*/ "","A_P3V_BAT_SCALED_EN","","FM_TPM_EN_PULSE","","FM_SKT0_FAULT_LED","","FM_SKT1_FAULT_LED", -+ /*56-63*/ "","","","","","RST_BMC_SMB_PCIE_MUX_N","","SURPRISE_RESET", -+ /*64-71*/ "PWRGD_S0_PWROK_CPU0","","","","","","","", -+ /*72-79*/ "","","","","","","","", -+ /*80-87*/ "","","","","","","","", -+ /*88-95*/ "","","","","","","","", -+ /*96-103*/ "","","","","","","","", -+ /*104-111*/ "","","","","","","","", -+ /*112-119*/ "","","","","","","","", -+ /*120-127*/ "","","","","","","","", -+ /*128-135*/ "","","","","","","","", -+ /*136-143*/ "","","","","","","","", -+ /*144-151*/ "","","","","","","","", -+ /*152-159*/ "","","","","","","","", -+ /*160-167*/ "","","","","","","","", -+ /*168-175*/ "","","","","","","","", -+ /*176-183*/ "","","","","","","","", -+ /*184-191*/ "","","","","","","","", -+ /*192-199*/ "","","","","","","","", -+ /*200-207*/ "","","","","","","","", -+ /*208-215*/ "","","","","","","","", -+ /*216-223*/ "","","","","","","",""; -+ -+ gpio_17 { -+ gpio-hog; -+ gpios = <17 GPIO_ACTIVE_HIGH>; -+ output-high; -+ line-name = "FM_CPU_FBRK_DEBUG_N"; -+ }; -+ gpio_19 { -+ gpio-hog; -+ gpios = <19 GPIO_ACTIVE_HIGH>; -+ output-high; -+ line-name = "FM_BMC_TRUST_N"; -+ }; -+ gpio_25 { -+ gpio-hog; -+ gpios = <25 GPIO_ACTIVE_HIGH>; -+ output-low; -+ line-name = "FM_BMC_ONCTL_N"; -+ }; -+ gpio_53 { -+ gpio-hog; -+ gpios = <53 GPIO_ACTIVE_HIGH>; -+ output-high; -+ line-name = "FM_SKT0_FAULT_LED"; -+ }; -+ gpio_61 { -+ gpio-hog; -+ gpios = <61 GPIO_ACTIVE_HIGH>; -+ output-high; -+ line-name = "RST_BMC_SMB_PCIE_MUX_N"; -+ }; -+ gpio_63 { -+ gpio-hog; -+ gpios = <63 GPIO_ACTIVE_HIGH>; -+ output-low; -+ line-name = "SURPRISE_RESET"; -+ }; -+}; -+ -+&peci0 { -+ status = "okay"; -+}; -+ -+&chassis { -+ status = "okay"; -+}; -+ -+&mdio0 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy0: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&mac0 { -+ status = "okay"; -+ -+ phy-mode = "rgmii-id"; -+ phy-handle = <ðphy0>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; -+}; -+ -+&jtag1 { -+ status = "okay"; -+}; -+ -+&gpio1 { -+ pinctrl-0 = <&pinctrl_i3c0_3_hv_voltage -+ &pinctrl_i3c0_driving &pinctrl_i3c1_driving -+ &pinctrl_i3c2_driving &pinctrl_i3c3_driving>; -+ pinctrl-names = "default"; -+ -+ gpio-line-names = -+ /*A0-A7*/ "","","","","","","","", -+ /*B0-B7*/ "","","","","","","","", -+ /*C0-C7*/ "","","","","","","","", -+ /*D0-D7*/ "","","","","","","","", -+ /*E0-E7*/ "","","","","FP_LED_STATUS_GREEN_CPLD_N","FP_LED_STATUS_AMBER_CPLD_N","","", -+ /*F0-F7*/ "","","","","","","","", -+ /*G0-G7*/ "","","","","","","","", -+ /*H0-H7*/ "","","","","","","","", -+ /*I0-I7*/ "","","","","","","","", -+ /*J0-J7*/ "","","","","","","","", -+ /*K0-K7*/ "","","","","","","","", -+ /*L0-L7*/ "","","","","","","","", -+ /*M0-M7*/ "","","","","","","","", -+ /*N0-N7*/ "","","","","","","","", -+ /*O0-O7*/ "","","","","","","","", -+ /*P0-P7*/ "","","","","","","","", -+ /*Q0-Q7*/ "","","","","","","","", -+ /*R0-R7*/ "","","","","","","","", -+ /*S0-S7*/ "","","","","","","","", -+ /*T0-T7*/ "","","","","","","","", -+ /*U0-U7*/ "","","","","","SCM_PHY_RST","","", -+ /*V0-V7*/ "","","","","","","","", -+ /*W0-W7*/ "","","","","","","","", -+ /*X0-X7*/ "","","","","","","","", -+ /*Y0-Y7*/ "","","","","IRQ_PMBUS1_ALERT_LVC3_N","FM_NVME_LVC3_ALERT_N","","", -+ /*Z0-Z7*/ "","","FM_NODE_ID0_N","FM_NODE_ID1_N","","PWRGD_AUX_PWRGD_PFR_CPU0","PWRGD_AUX_PWRGD_PFR_CPU1","", -+ /*AA0-AA7*/ "BMC_BOOT_DONE","","","","","","","", -+ /*AB0-AB7*/ "","","","","","","","", -+ /*AC0-AC7*/ "","","","","","","","", -+ /*AD0-AD7*/ "","","","","","","","", -+ /*AE0-AE7*/ "","","","","","","",""; -+}; -+ -+/* AST2700 A1 support SGPIO slave to 72*2 pins. */ -+/* The SGPIO slave table is defined in Chapter 7 of the AST2700 LTPI Design Guide v10.pdf. */ -+/* line 0:BMC_SGPI0(SCM_GPI0), 1:BMC_SGPO0(SCM_GPO0), 2:BMC_SGPI1(SCM_GPI1), 3:BMC_SGPO1(SCM_GPO1), etc... */ -+/* line 32:BMC_SGPI16(LTPI0_INL80), 33:BMC_SGPO16(LTPI0_ONL80), 34:LTPI0_INL81, 35:LTPI0_ONL81, etc... */ -+/* BMC_SGPI[15:0] = SCM_GPI0[15:0], BMC_SGPO[15:0] = BMC_SGPO0[15:0] */ -+/* BMC_SGPI[23:16] = LTPI0_INL[87:80], BMC_SGPO[23:16] = LTPI0_ONL[87:80] */ -+/* BMC_SGPI[31:24] = LTPI1_INL[87:80], BMC_SGPO[31:24] = LTPI1_ONL[87:80] */ -+/* BMC_SGPI[47:32] = LTPI0_INL[15:0], BMC_SGPO[47:32] = LTPI0_ONL[15:0] */ -+/* BMC_SGPI[63:48] = LTPI1_INL[15:0], BMC_SGPO[63:48] = LTPI1_ONL[15:0] */ -+/* BMC_SGPI[71:64] = SREG_GPO[7:0], BMC_SGPO[71:64] = SREG_GPI[7:0] */ -+/* The designe guide only define SCM_GPO9(FP_PWR_BTN_PFR_N) for PFR output pin. */ -+/* We use AST2700 SGPIOS line 18 (FP_PWR_BTN_PFR_N_BMC_IN) for x86-power-control power button input. */ -+&sgpios { -+ status = "okay"; -+ gpio-line-names = -+ /*00-07*/ "","","","","","","","", -+ /*08-15*/ "","","","","","","","", -+ /*16-23*/ "","","FP_PWR_BTN_PFR_N_BMC_IN","","","","","", -+ /*24-31*/ "","","","","","","","", -+ /*32-39*/ "","","","","","","","", -+ /*40-47*/ "","","","","","","","", -+ /*48-55*/ "","","","","","","","", -+ /*56-63*/ "","","","","","","","", -+ /*64-71*/ "","","","","","","","", -+ /*72-79*/ "","","","","","","","", -+ /*80-87*/ "","","","","","","","", -+ /*88-95*/ "","","","","","","","", -+ /*96-103*/ "","","","","","","","", -+ /*104-111*/ "","","","","","","","", -+ /*112-119*/ "","","","","","","","", -+ /*120-127*/ "","","","","","","","", -+ /*128-135*/ "","","","","","","","", -+ /*136-143*/ "","","","","","","",""; -+}; -+ -+&espi0 { -+ status = "okay"; -+ perif-dma-mode; -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi0_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ vw-pltrst-monitor; -+ oob-dma-mode; -+ flash-dma-mode; -+}; -+ -+#if 0 //eSPI1 and SD are multi-functional pin, SD default on -+&espi1 { -+ status = "okay"; -+ perif-dma-mode; -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ vw-pltrst-monitor; -+ oob-dma-mode; -+ flash-dma-mode; -+}; -+#endif -+ -+&lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <0>; -+}; -+ -+&lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <1>; -+}; -+ -+&lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <2>; -+}; -+ -+&lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <3>; -+}; -+ -+&lpc0_ibt { -+ status = "okay"; -+}; -+ -+&lpc0_mbox { -+ status = "okay"; -+}; -+ -+&lpc0_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+ -+&lpc0_uart_routing { -+ status = "okay"; -+}; -+ -+&lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <4>; -+}; -+ -+&lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <5>; -+}; -+ -+&lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <6>; -+}; -+ -+&lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <7>; -+}; -+ -+&lpc1_ibt { -+ status = "okay"; -+}; -+ -+&lpc1_mbox { -+ status = "okay"; -+}; -+ -+&lpc1_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+ -+&lpc1_uart_routing { -+ status = "okay"; -+}; -+ -+&video0 { -+ status = "okay"; -+ memory-region = <&video_engine_memory0>; -+}; -+ -+&video1 { -+ status = "okay"; -+ memory-region = <&video_engine_memory1>; -+}; -+ -+&disp_intf { -+ status = "okay"; -+}; -+ -+&rtc { -+ status = "okay"; -+}; -+ -+&rsss { -+ status = "okay"; -+}; -+ -+&ecdsa { -+ status = "okay"; -+}; -+ -+&hace { -+ status = "okay"; -+}; -+ -+&bmc_dev0 { -+ status = "okay"; -+ memory-region = <&bmc_dev0_memory>; -+}; -+ -+&xdma0 { -+ status = "okay"; -+ memory-region = <&xdma_memory0>; -+}; -+ -+&pcie_vuart0 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_vuart1 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <8>; -+}; -+ -+&pcie_lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <9>; -+}; -+ -+&pcie_lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <10>; -+}; -+ -+&pcie_lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <11>; -+}; -+ -+&pcie_lpc0_ibt { -+ status = "okay"; -+ bt-channel = <2>; -+}; -+ -+&bmc_dev1 { -+ status = "okay"; -+ memory-region = <&bmc_dev1_memory>; -+}; -+ -+&xdma1 { -+ status = "okay"; -+ memory-region = <&xdma_memory1>; -+}; -+ -+&pcie_vuart2 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_vuart3 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <12>; -+}; -+ -+&pcie_lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <13>; -+}; -+ -+&pcie_lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <14>; -+}; -+ -+&pcie_lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <15>; -+}; -+ -+&pcie_lpc1_ibt { -+ status = "okay"; -+ bt-channel = <3>; -+}; -+ -+&mctp0 { -+ status = "okay"; -+ memory-region = <&mctp0_reserved>; -+}; -+ -+&mctp1 { -+ status = "okay"; -+ memory-region = <&mctp1_reserved>; -+}; -+ -+/* Enable i2c0~i2c4 for LTPI testing. */ -+&i2c0 { -+ /* SMB_PMBUS1_SCM */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&i2c1 { -+ /* SMB_IPMB_SCL1 */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&i2c2 { -+ /* SMB_CPLD_SCL2 */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&i2c3 { -+ /* SMB_PMBUS2_SCM */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&i2c4 { -+ /* SMB_PMBUS1_SCM */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+/* Default i2c5 is tunnelded to LTPI. */ -+/* Enable i2c5 pinctrl for testing on board LM75. */ -+&i2c5 { -+ /* SMB_TMP_BMC */ -+ status = "okay"; -+}; -+ -+/* AST2700 i2c8 -> AST1060 i2c5 for PCH mailbox emulation test. */ -+&i2c8 { -+ /* SMB_PCIE_SCM */ -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c9 { -+ /* SMB_HOST_BMC */ -+ status = "okay"; -+ eeprom@50 { -+ compatible = "atmel,24c04"; -+ reg = <0x50>; -+ pagesize = <16>; -+ }; -+}; -+ -+/* AST2700 A1 i2c10 -> AST1060 i2c0 for PFR mailbox. */ -+&i2c10 { -+ /* SMB_HSBP_BMC */ -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c11 { -+ /* BMC_HPM_I3C_I2C_13 */ -+ status = "okay"; -+}; -+ -+&uphy3a { -+ status = "okay"; -+}; -+ -+&uphy3b { -+ status = "okay"; -+}; -+ -+&vhuba0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; -+}; -+ -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; -+ -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ -+&vhubb1 { -+ status = "okay"; -+}; -+ -+&vhubc { -+ status = "okay"; -+}; -+ -+&ehci3 { -+ status = "okay"; -+}; -+ -+&uhci1 { -+ status = "okay"; -+ memory-region = <&uhci1_reserved>; -+}; -+ -+&wdt0 { -+ status = "okay"; -+}; -+ -+&wdt1 { -+ status = "okay"; -+}; -+ -+&otp { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts -new file mode 100644 -index 000000000..a2caa026a ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb-dual.dts -@@ -0,0 +1,218 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-dcscm_ast1700a1-evb.dts" -+#include "aspeed-ltpi1.dtsi" -+ -+/ { -+ model = "AST2700A1-DCSCM_AST1700A1-EVB-DUAL"; -+ -+ ltpi1-iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <<pi1_adc0 0>, <<pi1_adc0 1>, <<pi1_adc0 2>, <<pi1_adc0 3>, -+ <<pi1_adc0 4>, <<pi1_adc0 5>, <<pi1_adc0 6>, <<pi1_adc0 7>, -+ <<pi1_adc1 0>, <<pi1_adc1 1>, <<pi1_adc1 2>, <<pi1_adc1 3>, -+ <<pi1_adc1 4>, <<pi1_adc1 5>, <<pi1_adc1 6>, <<pi1_adc1 7>; -+ }; -+}; -+ -+<pi1_adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; -+ -+<pi1_adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; -+ -+<pi1 { -+ i2c-tunneling = <0x0>; -+ status = "okay"; -+}; -+ -+<pi1_gpio { -+ status = "okay"; -+}; -+ -+<pi1_i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi1_i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi1_i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i2c6 { -+ status = "disabled"; -+}; -+ -+&i2c7 { -+ status = "disabled"; -+}; -+ -+// The following I2C buses require enabling according to the ast2700-dcscm.dts. -+// i2c8 / i2c9 / i2c10 -+ -+&i2c11 { -+ status = "disabled"; -+}; -+ -+<pi1_i2c0 { -+ status = "okay"; -+}; -+ -+<pi1_i2c1 { -+ status = "okay"; -+}; -+ -+<pi1_i2c2 { -+ status = "okay"; -+}; -+ -+<pi1_i2c3 { -+ status = "okay"; -+}; -+ -+<pi1_i2c4 { -+ status = "okay"; -+}; -+ -+<pi1_i2c5 { -+ status = "okay"; -+}; -+ -+<pi1_i2c6 { -+ status = "okay"; -+}; -+ -+<pi1_i2c7 { -+ status = "okay"; -+}; -+ -+<pi1_i2c8 { -+ status = "okay"; -+}; -+ -+<pi1_i2c9 { -+ status = "okay"; -+}; -+ -+<pi1_i2c10 { -+ status = "okay"; -+}; -+ -+<pi1_i2c11 { -+ status = "okay"; -+}; -+ -+<pi1_i2c12 { -+ status = "okay"; -+}; -+ -+<pi1_i2c13 { -+ status = "okay"; -+}; -+ -+<pi1_i2c14 { -+ status = "okay"; -+}; -+ -+<pi1_i2c15 { -+ status = "okay"; -+}; -+ -+&uart8 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts -new file mode 100644 -index 000000000..d8c96a669 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1700a1-evb.dts -@@ -0,0 +1,456 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-dcscm.dts" -+#include "aspeed-ltpi0.dtsi" -+ -+/ { -+ model = "AST2700A1-DCSCM_AST1700A1-EVB"; -+ -+ ltpi_fan0: ltpi-pwm-fan0 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 0 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan1: ltpi-pwm-fan1 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 1 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan2: ltpi-pwm-fan2 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 2 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan3: ltpi-pwm-fan3 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 3 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan4: ltpi-pwm-fan4 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 4 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan5: ltpi-pwm-fan5 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 5 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan6: ltpi-pwm-fan6 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 6 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan7: ltpi-pwm-fan7 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 7 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan8: ltpi-pwm-fan8 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 8 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan9: ltpi-pwm-fan9 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 9 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan10: ltpi-pwm-fan10 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 10 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan11: ltpi-pwm-fan11 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 11 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan12: ltpi-pwm-fan12 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 12 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan13: ltpi-pwm-fan13 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 13 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan14: ltpi-pwm-fan14 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 14 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan15: ltpi-pwm-fan15 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 15 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi0-iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <<pi0_adc0 0>, <<pi0_adc0 1>, <<pi0_adc0 2>, <<pi0_adc0 3>, -+ <<pi0_adc0 4>, <<pi0_adc0 5>, <<pi0_adc0 6>, <<pi0_adc0 7>, -+ <<pi0_adc1 0>, <<pi0_adc1 1>, <<pi0_adc1 2>, <<pi0_adc1 3>, -+ <<pi0_adc1 4>, <<pi0_adc1 5>, <<pi0_adc1 6>, <<pi0_adc1 7>; -+ }; -+}; -+ -+<pi0_pwm_tach { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_ltpi0_pwm0_default &pinctrl_ltpi0_pwm1_default -+ &pinctrl_ltpi0_pwm2_default &pinctrl_ltpi0_pwm3_default -+ &pinctrl_ltpi0_pwm4_default &pinctrl_ltpi0_pwm5_default -+ &pinctrl_ltpi0_pwm6_default &pinctrl_ltpi0_pwm7_default -+ &pinctrl_ltpi0_pwm8_default -+ &pinctrl_ltpi0_tach0_default &pinctrl_ltpi0_tach1_default -+ &pinctrl_ltpi0_tach2_default &pinctrl_ltpi0_tach3_default -+ &pinctrl_ltpi0_tach4_default &pinctrl_ltpi0_tach5_default -+ &pinctrl_ltpi0_tach6_default &pinctrl_ltpi0_tach7_default -+ &pinctrl_ltpi0_tach8_default &pinctrl_ltpi0_tach9_default -+ &pinctrl_ltpi0_tach10_default &pinctrl_ltpi0_tach11_default -+ &pinctrl_ltpi0_tach12_default &pinctrl_ltpi0_tach13_default -+ &pinctrl_ltpi0_tach14_default &pinctrl_ltpi0_tach15_default>; -+ ltpi_fan0 { -+ tach-ch = /bits/ 8 <0x0>; -+ }; -+ ltpi_fan1 { -+ tach-ch = /bits/ 8 <0x1>; -+ }; -+ ltpi_fan2 { -+ tach-ch = /bits/ 8 <0x2>; -+ }; -+ ltpi_fan3 { -+ tach-ch = /bits/ 8 <0x3>; -+ }; -+ ltpi_fan4 { -+ tach-ch = /bits/ 8 <0x4>; -+ }; -+ ltpi_fan5 { -+ tach-ch = /bits/ 8 <0x5>; -+ }; -+ ltpi_fan6 { -+ tach-ch = /bits/ 8 <0x6>; -+ }; -+ ltpi_fan7 { -+ tach-ch = /bits/ 8 <0x7>; -+ }; -+ ltpi_fan8 { -+ tach-ch = /bits/ 8 <0x8>; -+ }; -+ ltpi_fan9 { -+ tach-ch = /bits/ 8 <0x9>; -+ }; -+ ltpi_fan10 { -+ tach-ch = /bits/ 8 <0xA>; -+ }; -+ ltpi_fan11 { -+ tach-ch = /bits/ 8 <0xB>; -+ }; -+ ltpi_fan12 { -+ tach-ch = /bits/ 8 <0xC>; -+ }; -+ ltpi_fan13 { -+ tach-ch = /bits/ 8 <0xD>; -+ }; -+ ltpi_fan14 { -+ tach-ch = /bits/ 8 <0xE>; -+ }; -+ ltpi_fan15 { -+ tach-ch = /bits/ 8 <0xF>; -+ }; -+}; -+ -+&sgpios { -+ /delete-property/ gpio-line-names; -+}; -+ -+<pi0_gpio { -+ /delete-property/ gpio-line-names; -+ /delete-node/ gpio_17; -+ /delete-node/ gpio_19; -+ /delete-node/ gpio_25; -+ /delete-node/ gpio_53; -+ /delete-node/ gpio_61; -+ /delete-node/ gpio_63; -+}; -+ -+<pi0_adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_ltpi0_adc0_default &pinctrl_ltpi0_adc1_default -+ &pinctrl_ltpi0_adc2_default &pinctrl_ltpi0_adc3_default -+ &pinctrl_ltpi0_adc4_default &pinctrl_ltpi0_adc5_default -+ &pinctrl_ltpi0_adc6_default &pinctrl_ltpi0_adc7_default>; -+}; -+ -+<pi0_adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_ltpi0_adc8_default &pinctrl_ltpi0_adc9_default -+ &pinctrl_ltpi0_adc10_default &pinctrl_ltpi0_adc11_default -+ &pinctrl_ltpi0_adc12_default &pinctrl_ltpi0_adc13_default -+ &pinctrl_ltpi0_adc14_default &pinctrl_ltpi0_adc15_default>; -+}; -+ -+<pi0 { -+ i2c-tunneling = <0x0>; -+ status = "okay"; -+}; -+ -+<pi0_i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i2c0 { -+ status = "disabled"; -+}; -+ -+&i2c1 { -+ status = "disabled"; -+}; -+ -+&i2c2 { -+ status = "disabled"; -+}; -+ -+&i2c3 { -+ status = "disabled"; -+}; -+ -+&i2c4 { -+ status = "disabled"; -+}; -+ -+&i2c5 { -+ status = "disabled"; -+}; -+ -+<pi0_i2c0 { -+ status = "okay"; -+}; -+ -+<pi0_i2c1 { -+ status = "okay"; -+}; -+ -+<pi0_i2c2 { -+ status = "okay"; -+}; -+ -+<pi0_i2c3 { -+ status = "okay"; -+}; -+ -+<pi0_i2c4 { -+ status = "okay"; -+}; -+ -+<pi0_i2c5 { -+ status = "okay"; -+}; -+ -+<pi0_i2c6 { -+ status = "okay"; -+}; -+ -+<pi0_i2c7 { -+ status = "okay"; -+}; -+ -+<pi0_i2c8 { -+ status = "okay"; -+}; -+ -+<pi0_i2c9 { -+ status = "okay"; -+}; -+ -+<pi0_i2c10 { -+ status = "okay"; -+}; -+ -+<pi0_i2c11 { -+ status = "okay"; -+}; -+ -+<pi0_i2c12 { -+ status = "okay"; -+}; -+ -+<pi0_i2c13 { -+ status = "okay"; -+}; -+ -+<pi0_i2c14 { -+ status = "okay"; -+}; -+ -+<pi0_i2c15 { -+ status = "okay"; -+}; -+ -+&uart3 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts -new file mode 100644 -index 000000000..357a320d7 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-dcscm_ast1800-evb.dts -@@ -0,0 +1,436 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-dcscm.dts" -+#include "aspeed-ltpi1800.dtsi" -+ -+/ { -+ model = "AST2700A1-DCSCM_AST1800-EVB"; -+ -+ ltpi_fan0: ltpi-pwm-fan0 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 0 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan1: ltpi-pwm-fan1 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 1 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan2: ltpi-pwm-fan2 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 2 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan3: ltpi-pwm-fan3 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 3 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan4: ltpi-pwm-fan4 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 4 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan5: ltpi-pwm-fan5 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 5 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan6: ltpi-pwm-fan6 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 6 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan7: ltpi-pwm-fan7 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 7 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan8: ltpi-pwm-fan8 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 8 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan9: ltpi-pwm-fan9 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 9 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan10: ltpi-pwm-fan10 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 10 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan11: ltpi-pwm-fan11 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 11 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan12: ltpi-pwm-fan12 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 12 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan13: ltpi-pwm-fan13 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 13 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan14: ltpi-pwm-fan14 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 14 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi_fan15: ltpi-pwm-fan15 { -+ compatible = "pwm-fan"; -+ pwms = <<pi0_pwm_tach 15 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ ltpi0-iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <<pi0_adc0 0>, <<pi0_adc0 1>, <<pi0_adc0 2>, <<pi0_adc0 3>, -+ <<pi0_adc0 4>, <<pi0_adc0 5>, <<pi0_adc0 6>, <<pi0_adc0 7>, -+ <<pi0_adc1 0>, <<pi0_adc1 1>, <<pi0_adc1 2>, <<pi0_adc1 3>, -+ <<pi0_adc1 4>, <<pi0_adc1 5>, <<pi0_adc1 6>, <<pi0_adc1 7>; -+ }; -+}; -+ -+<pi0_jtag { -+ status = "okay"; -+}; -+ -+<pi0_pwm_tach { -+ status = "okay"; -+ ltpi_fan0 { -+ tach-ch = /bits/ 8 <0x0>; -+ }; -+ ltpi_fan1 { -+ tach-ch = /bits/ 8 <0x1>; -+ }; -+ ltpi_fan2 { -+ tach-ch = /bits/ 8 <0x2>; -+ }; -+ ltpi_fan3 { -+ tach-ch = /bits/ 8 <0x3>; -+ }; -+ ltpi_fan4 { -+ tach-ch = /bits/ 8 <0x4>; -+ }; -+ ltpi_fan5 { -+ tach-ch = /bits/ 8 <0x5>; -+ }; -+ ltpi_fan6 { -+ tach-ch = /bits/ 8 <0x6>; -+ }; -+ ltpi_fan7 { -+ tach-ch = /bits/ 8 <0x7>; -+ }; -+ ltpi_fan8 { -+ tach-ch = /bits/ 8 <0x8>; -+ }; -+ ltpi_fan9 { -+ tach-ch = /bits/ 8 <0x9>; -+ }; -+ ltpi_fan10 { -+ tach-ch = /bits/ 8 <0xA>; -+ }; -+ ltpi_fan11 { -+ tach-ch = /bits/ 8 <0xB>; -+ }; -+ ltpi_fan12 { -+ tach-ch = /bits/ 8 <0xC>; -+ }; -+ ltpi_fan13 { -+ tach-ch = /bits/ 8 <0xD>; -+ }; -+ ltpi_fan14 { -+ tach-ch = /bits/ 8 <0xE>; -+ }; -+ ltpi_fan15 { -+ tach-ch = /bits/ 8 <0xF>; -+ }; -+}; -+ -+&sgpios { -+ /delete-property/ gpio-line-names; -+}; -+ -+<pi0_gpio { -+ /delete-property/ gpio-line-names; -+ /delete-node/ gpio_17; -+ /delete-node/ gpio_19; -+ /delete-node/ gpio_25; -+ /delete-node/ gpio_53; -+ /delete-node/ gpio_61; -+ /delete-node/ gpio_63; -+}; -+ -+<pi0_adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; -+ -+<pi0_adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; -+ -+<pi0 { -+ i2c-tunneling = <0x0>; -+}; -+ -+<pi0_i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+<pi0_i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+<pi0_i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i2c0 { -+ status = "disabled"; -+}; -+ -+&i2c1 { -+ status = "disabled"; -+}; -+ -+&i2c2 { -+ status = "disabled"; -+}; -+ -+&i2c3 { -+ status = "disabled"; -+}; -+ -+&i2c4 { -+ status = "disabled"; -+}; -+ -+&i2c5 { -+ status = "disabled"; -+}; -+ -+<pi0_i2c0 { -+ status = "okay"; -+}; -+ -+<pi0_i2c1 { -+ status = "okay"; -+}; -+ -+<pi0_i2c2 { -+ status = "okay"; -+}; -+ -+<pi0_i2c3 { -+ status = "okay"; -+}; -+ -+<pi0_i2c4 { -+ status = "okay"; -+}; -+ -+<pi0_i2c5 { -+ status = "okay"; -+}; -+ -+<pi0_i2c6 { -+ status = "okay"; -+}; -+ -+<pi0_i2c7 { -+ status = "okay"; -+}; -+ -+<pi0_i2c8 { -+ status = "okay"; -+}; -+ -+<pi0_i2c9 { -+ status = "okay"; -+}; -+ -+<pi0_i2c10 { -+ status = "okay"; -+}; -+ -+<pi0_i2c11 { -+ status = "okay"; -+}; -+ -+<pi0_i2c12 { -+ status = "okay"; -+}; -+ -+<pi0_i2c13 { -+ status = "okay"; -+}; -+ -+<pi0_i2c14 { -+ status = "okay"; -+}; -+ -+<pi0_i2c15 { -+ status = "okay"; -+}; -+ -+&uart3 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts -new file mode 100644 -index 000000000..c19544c52 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-256-abr.dts -@@ -0,0 +1,40 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-evb.dts" -+ -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "bmc"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+#include "aspeed-evb-flash-layout-256-abr.dtsi" -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+ -+ flash@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+}; -+ -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts -new file mode 100644 -index 000000000..2f6914d71 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s0.dts -@@ -0,0 +1,367 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include "ast2700a1-evb.dts" -+#include -+ -+/ { -+ model = "AST2700A1 EVB Test S0 Test"; -+}; -+ -+&pcie2 { -+ status = "disabled"; -+}; -+ -+&mdio2 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&sgmii { -+ status = "okay"; -+}; -+ -+&mac2 { -+ status = "okay"; -+ -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; -+}; -+ -+&sdio_controller { -+ status = "disabled"; -+}; -+ -+&sdhci { -+ status = "disabled"; -+}; -+ -+&espi1 { -+ status = "okay"; -+ perif-dma-mode; -+#if 0 //TODO: No enough memory for espi1 MMBI -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+#endif -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ oob-dma-mode; -+ flash-dma-mode; -+}; -+ -+&can0 { -+ status = "disabled"; -+}; -+ -+// S0 use 0x10 as its slave address -+&i2c0 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c1 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c2 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c3 { -+ clock-frequency = <1000000>; -+ debounce-level = <6>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c4 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c5 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c6 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c7 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c8 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c9 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c10 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c11 { -+ clock-frequency = <1000000>; -+ debounce-level = <6>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c12 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c13 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c14 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c15 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@10 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c1 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06011000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c3 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06013000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c5 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06015000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c7 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06017000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c9 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06019000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c11 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601B000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c13 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601D000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c15 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601F000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts -new file mode 100644 -index 000000000..d4ed9e460 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb-s1.dts -@@ -0,0 +1,481 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include "ast2700a1-evb.dts" -+#include -+ -+/ { -+ model = "AST2700A1 EVB Test S1 Test"; -+}; -+ -+&bmc_dev0 { -+ status = "disabled"; -+}; -+ -+&xdma0 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart0 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs0 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs2 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_ibt { -+ status = "disabled"; -+}; -+ -+&pcie0_mmbi0 { -+ status = "disabled"; -+}; -+ -+&pcie0 { -+ status = "okay"; -+}; -+ -+&bmc_dev1 { -+ status = "disabled"; -+}; -+ -+&xdma1 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart2 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs0 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs2 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_ibt { -+ status = "disabled"; -+}; -+ -+&pcie1_mmbi4 { -+ status = "disabled"; -+}; -+ -+&pcie1 { -+ status = "okay"; -+}; -+ -+&sdio_controller { -+ status = "disabled"; -+}; -+ -+&sdhci { -+ status = "disabled"; -+}; -+ -+&espi1 { -+ status = "okay"; -+ perif-dma-mode; -+#if 0 // TODO: No enough memory for espi1 MMBI -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+#endif -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ oob-dma-mode; -+ flash-dma-mode; -+}; -+ -+&can0 { -+ status = "disabled"; -+}; -+ -+// S1 use 0x12 as its slave address -+&i2c0 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c1 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c2 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c3 { -+ clock-frequency = <1000000>; -+ debounce-level = <6>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c4 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c5 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c6 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c7 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c8 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c9 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c10 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c11 { -+ clock-frequency = <1000000>; -+ debounce-level = <6>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c12 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c13 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c14 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i2c15 { -+ clock-frequency = <1000000>; -+ debounce-level = <4>; -+ status = "okay"; -+ multi-master; -+ mctp-controller; -+ mctp@12 { -+ compatible = "mctp-i2c-controller"; -+ reg = <(0x12 | I2C_OWN_SLAVE_ADDRESS)>; -+ }; -+}; -+ -+&i3c0 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c2 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c4 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c6 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c8 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c10 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c12 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c14 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&sgpios { -+ status = "disabled"; -+}; -+ -+&mac0 { -+ status = "okay"; -+ -+ phy-mode = "rmii"; -+ use-ncsi; -+ -+ pinctrl-names = "default"; -+ /* If you want to use RMII0 RCLKO as internal clock for RMII, -+ * add &pinctrl_rmii0_rclko_default in pinctrl-0. -+ */ -+ pinctrl-0 = <&pinctrl_rmii0_default>; -+}; -+ -+&mac1 { -+ status = "okay"; -+ -+ phy-mode = "rmii"; -+ use-ncsi; -+ -+ pinctrl-names = "default"; -+ /* If you want to use RMII1 RCLKO as internal clock for RMII, -+ * add &pinctrl_rmii1_rclko_default in pinctrl-0. -+ */ -+ pinctrl-0 = <&pinctrl_rmii1_default>; -+}; -+ -+&syscon1 { -+ mac0-clk-delay = <0 0 -+ 0 0 -+ 0 0>; -+ mac1-clk-delay = <0 0 -+ 0 0 -+ 0 0>; -+}; -+ -+&vhuba0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ad0_default>; -+}; -+ -+&uphy2a { -+ status = "okay"; -+}; -+ -+&usb3ahp { -+ status = "disabled"; -+}; -+ -+&usb3bhp { -+ status = "disabled"; -+}; -+ -+&vhubb0 { -+ status = "okay"; -+}; -+ -+&vhubb1 { -+ status = "disabled"; -+}; -+ -+&vhubc { -+ status = "disabled"; -+}; -+ -+&vhubd { -+ status = "okay"; -+}; -+ -+&ehci2 { -+ status = "okay"; -+}; -+ -+&ehci3 { -+ status = "disabled"; -+}; -+ -+&pcie2 { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts -new file mode 100644 -index 000000000..c66d02e95 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-evb.dts -@@ -0,0 +1,1265 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+#include "aspeed-g7.dtsi" -+#include -+#include -+#include -+ -+#define DUAL_NODE 0 // 1: DUAL_NODE, 0: SINGLE_NODE -+#define PCIE0_EP 1 // 1: EP, 0: RC -+#define PCIE1_EP 1 // 1: EP, 0: RC -+#define PCIE2_RC 1 // 1: RC, 0: SGMII -+ -+/ { -+ model = "AST2700A1 EVB"; -+ compatible = "aspeed,ast2700-evb", "aspeed,ast2700"; -+ -+ chosen { -+ stdout-path = "serial12:115200n8"; -+ }; -+ -+ memory@400000000 { -+ device_type = "memory"; -+ reg = <0x4 0x00000000 0x0 0x40000000>; -+ }; -+ -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ #include "ast2700-reserved-mem.dtsi" -+ -+ video_engine_memory0: video0 { -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+ video_engine_memory1: video1 { -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ -+#if 0 -+ gfx_memory: framebuffer { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+#endif -+ -+ espi0_mcyc_memory: mcyc0 { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ }; -+ -+ fan0: pwm-fan0 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 0 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan1: pwm-fan1 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 1 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan2: pwm-fan2 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 2 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan3: pwm-fan3 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 3 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan4: pwm-fan4 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 4 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan5: pwm-fan5 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 5 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan6: pwm-fan6 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 6 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan7: pwm-fan7 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 7 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ fan8: pwm-fan8 { -+ compatible = "pwm-fan"; -+ pwms = <&pwm_tach 8 40000 0>; /* Target freq:25 kHz */ -+ cooling-min-state = <0>; -+ cooling-max-state = <3>; -+ #cooling-cells = <2>; -+ cooling-levels = <0 15 128 255>; -+ }; -+ -+ iio-hwmon { -+ compatible = "iio-hwmon"; -+ status = "okay"; -+ io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, -+ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, -+ <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>, -+ <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>; -+ }; -+}; -+ -+&pwm_tach { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default -+ &pinctrl_pwm2_default &pinctrl_pwm3_default -+ &pinctrl_pwm4_default &pinctrl_pwm5_default -+ &pinctrl_pwm6_default &pinctrl_pwm7_default -+ &pinctrl_pwm8_default -+ &pinctrl_tach0_default &pinctrl_tach1_default -+ &pinctrl_tach2_default &pinctrl_tach3_default -+ &pinctrl_tach4_default &pinctrl_tach5_default -+ &pinctrl_tach6_default &pinctrl_tach7_default -+ &pinctrl_tach8_default &pinctrl_tach9_default -+ &pinctrl_tach10_default &pinctrl_tach11_default -+ &pinctrl_tach12_default &pinctrl_tach13_default -+ &pinctrl_tach14_default &pinctrl_tach15_default>; -+ fan-0 { -+ tach-ch = /bits/ 8 <0x0>; -+ }; -+ fan-1 { -+ tach-ch = /bits/ 8 <0x1>; -+ }; -+ fan-2 { -+ tach-ch = /bits/ 8 <0x2>; -+ }; -+ fan-3 { -+ tach-ch = /bits/ 8 <0x3>; -+ }; -+ fan-4 { -+ tach-ch = /bits/ 8 <0x4>; -+ }; -+ fan-5 { -+ tach-ch = /bits/ 8 <0x5>; -+ }; -+ fan-6 { -+ tach-ch = /bits/ 8 <0x6>; -+ }; -+ fan-7 { -+ tach-ch = /bits/ 8 <0x7>; -+ }; -+ fan-8 { -+ tach-ch = /bits/ 8 <0x8>; -+ }; -+ fan-9 { -+ tach-ch = /bits/ 8 <0x9>; -+ }; -+ fan-10 { -+ tach-ch = /bits/ 8 <0xA>; -+ }; -+ fan-11 { -+ tach-ch = /bits/ 8 <0xB>; -+ }; -+ fan-12 { -+ tach-ch = /bits/ 8 <0xC>; -+ }; -+ fan-13 { -+ tach-ch = /bits/ 8 <0xD>; -+ }; -+ fan-14 { -+ tach-ch = /bits/ 8 <0xE>; -+ }; -+ fan-15 { -+ tach-ch = /bits/ 8 <0xF>; -+ }; -+}; -+ -+&edac { -+ status = "okay"; -+}; -+ -+&mctp0 { -+ status = "okay"; -+ memory-region = <&mctp0_reserved>; -+}; -+ -+&mctp1 { -+ status = "okay"; -+ memory-region = <&mctp1_reserved>; -+}; -+ -+&mctp2 { -+ status = "okay"; -+ memory-region = <&mctp2_reserved>; -+}; -+ -+&sgpiom0 { -+ status = "okay"; -+}; -+ -+&sgpiom1 { -+ status = "okay"; -+}; -+ -+&jtag1 { -+ status = "okay"; -+}; -+ -+&adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default -+ &pinctrl_adc2_default &pinctrl_adc3_default -+ &pinctrl_adc4_default &pinctrl_adc5_default -+ &pinctrl_adc6_default &pinctrl_adc7_default>; -+}; -+ -+&adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default -+ &pinctrl_adc10_default &pinctrl_adc11_default -+ &pinctrl_adc12_default &pinctrl_adc13_default -+ &pinctrl_adc14_default &pinctrl_adc15_default>; -+}; -+ -+&pinctrl0 { -+ pinctrl_emmcclk_driving: emmcclk-driving { -+ pins = "AC14"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_emmccmd_driving: emmccmd-driving { -+ pins = "AE15"; -+ drive-strength = <1>; -+ }; -+ pinctrl_emmc4bit_driving: emmcdat-driving { -+ pins = "AD14", "AE14", "AF14", "AB13"; -+ drive-strength = <1>; -+ }; -+ -+ pinctrl_emmc8bit_driving: emmcdat-driving { -+ pins = "AD14", "AE14", "AF14", "AB13", "AF13", "AC13", "AD13", "AE13"; -+ drive-strength = <1>; -+ }; -+}; -+ -+&pinctrl1 { -+ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { -+ pins = "U25"; -+ power-source = <1800>; -+ }; -+ -+ pinctrl_i3c0_driving: i3c0-driving { -+ pins = "U25", "U26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c1_driving: i3c1-driving { -+ pins = "Y26", "AA24"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c2_driving: i3c2-driving { -+ pins = "R25", "AA26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c3_driving: i3c3-driving { -+ pins = "R26", "Y25"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c12_15_hv_voltage: i3chv-voltage { -+ pins = "W25"; -+ power-source = <1800>; -+ }; -+ -+ pinctrl_i3c12_driving: i3c12-driving { -+ pins = "W25", "Y23"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c13_driving: i3c13-driving { -+ pins = "Y24", "W21"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c14_driving: i3c14-driving { -+ pins = "AA23", "AC22"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c15_driving: i3c15-driving { -+ pins = "AB22", "Y21"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_rgmii0_driving: rgmii0-driving { -+ pins = "C20", "C19", "A8", "R14", "A7", "P14", -+ "D20", "A6", "B6", "N14", "B7", "B8"; -+ drive-strength = <1>; -+ }; -+ -+ pinctrl_rgmii1_driving: rgmii1-driving { -+ pins = "D19", "C19", "D15", "B12", "B10", "P13", -+ "C18", "C6", "C7", "D7", "N13", "C8"; -+ drive-strength = <1>; -+ }; -+}; -+ -+&gpio1 { -+ pinctrl-0 = <&pinctrl_i3c0_3_hv_voltage &pinctrl_i3c12_15_hv_voltage -+ &pinctrl_i3c0_driving &pinctrl_i3c1_driving -+ &pinctrl_i3c2_driving &pinctrl_i3c3_driving -+ &pinctrl_i3c12_driving &pinctrl_i3c13_driving -+ &pinctrl_i3c14_driving &pinctrl_i3c15_driving>; -+ pinctrl-names = "default"; -+}; -+ -+&i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; -+ -+&i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; -+ -+&uart12 { -+ status = "okay"; -+}; -+ -+#if 0 -+&vuart0 { -+ virtual; -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ status = "okay"; -+}; -+#endif -+ -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "bmc"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+#include "aspeed-evb-flash-layout-128.dtsi" -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+ -+ flash@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+}; -+ -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; -+ -+&spi1 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi1:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; -+ -+#if 1 -+&spi2 { -+ compatible = "aspeed,ast2700-spi-txrx"; -+ pinctrl-0 = <&pinctrl_spi2_default>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ -+ tpm0: tpmdev@0 { -+ compatible = "tcg,tpm_tis-spi"; -+ spi-max-frequency = <25000000>; -+ reg = <0>; -+ status = "okay"; -+ }; -+}; -+#else -+&spi2 { -+ compatible = "aspeed,ast2700-spi"; -+ pinctrl-0 = <&pinctrl_spi2_default &pinctrl_spi2_cs1_default>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ -+ flash@0 { -+ status = "okay"; -+ reg = < 0 >; -+ compatible = "jedec,spi-nor"; -+ m25p,fast-read; -+ label = "spi2:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ reg = < 1 >; -+ compatible = "jedec,spi-nor"; -+ m25p,fast-read; -+ label = "spi2:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; -+#endif -+ -+&can0 { -+ status = "okay"; -+}; -+ -+&emmc_controller { -+ status = "okay"; -+ mmc-hs200-1_8v; -+}; -+ -+&emmc { -+ status = "okay"; -+#if 1 -+ bus-width = <4>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_emmc_default -+ &pinctrl_emmcclk_driving -+ &pinctrl_emmccmd_driving -+ &pinctrl_emmc4bit_driving>; -+#else -+ bus-width = <8>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_emmc_default -+ &pinctrl_emmcg8_default -+ &pinctrl_emmcclk_driving -+ &pinctrl_emmccmd_driving -+ &pinctrl_emmc8bit_driving>; -+#endif -+ -+ non-removable; -+ max-frequency = <200000000>; -+}; -+ -+&ufs_controller { -+ status = "okay"; -+}; -+ -+&ufs { -+ status = "okay"; -+ lanes-per-direction = <2>; -+ ref-clk-freq = <26000000>; -+}; -+ -+&chassis { -+ status = "okay"; -+}; -+ -+&mdio0 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy0: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&mdio1 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy1: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ /* For DDR5 board */ -+ ti,rx-internal-delay = ; -+ ti,tx-internal-delay = ; -+ }; -+}; -+ -+&mac0 { -+ status = "okay"; -+ -+ phy-mode = "rgmii-id"; -+ phy-handle = <ðphy0>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; -+}; -+ -+&mac1 { -+ status = "okay"; -+ -+ phy-mode = "rgmii-id"; -+ phy-handle = <ðphy1>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_rgmii1_driving>; -+}; -+ -+#if 0 // Default to disable RC & SGMII -+#define PCIE2_RC 1 // 1: RC, 0: SGMII -+#if PCIE2_RC -+&pcie2 { -+ status = "okay"; -+}; -+#else -+&mdio2 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; -+ -+&sgmii { -+ status = "okay"; -+}; -+ -+&mac2 { -+ status = "okay"; -+ -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; -+}; -+#endif -+#endif -+ -+&espi0 { -+ status = "okay"; -+ perif-dma-mode; -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi0_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ memory-region = <&espi0_mcyc_memory>; -+ perif-rtc-enable; -+ vw-pltrst-monitor; -+ oob-dma-mode; -+ flash-dma-mode; -+#if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten -+ flash-edaf-mode = <0x0>; -+ flash-edaf-tgt-addr = <&edaf0>; -+#endif -+}; -+ -+&rtc_over_espi0 { -+ status = "okay"; -+}; -+ -+/* Enable UART2 and UART9 for obmc-console. */ -+&uart2 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&uart9 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+#if DUAL_NODE -+&espi1 { -+ status = "okay"; -+ perif-dma-mode; -+ perif-mmbi-enable; -+ perif-mmbi-src-addr = <0x0 0xa8000000>; -+ perif-mmbi-tgt-memory = <&espi1_mmbi_memory>; -+ perif-mmbi-instance-num = <0x1>; -+ perif-mcyc-enable; -+ perif-mcyc-src-addr = <0x0 0x98000000>; -+ perif-mcyc-size = <0x0 0x10000>; -+ perif-rtc-enable; -+ vw-pltrst-monitor; -+ oob-dma-mode; -+ flash-dma-mode; -+#if 0 // eDAF mode: Change 1 to enable MIX mode in Linux, but HW mode in SPL would be overwritten -+ flash-edaf-mode = <0x0>; -+ flash-edaf-tgt-addr = <&edaf1>; -+#endif -+}; -+ -+&rtc_over_espi1 { -+ status = "okay"; -+}; -+ -+/* Enable UART7 and UART10 for obmc-console. */ -+&uart7 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+ -+&uart10 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+#endif /* DUAL_NODE */ -+ -+&lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <0>; -+}; -+ -+&lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <1>; -+}; -+ -+&lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <2>; -+}; -+ -+&lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <3>; -+}; -+ -+&lpc0_ibt { -+ status = "okay"; -+}; -+ -+&lpc0_mbox { -+ status = "okay"; -+}; -+ -+#if 1 -+&lpc0_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+#else -+&lpc0_pcc { -+ status = "okay"; -+ pcc-ports = <0x80>; -+}; -+#endif -+ -+&lpc0_uart_routing { -+ status = "okay"; -+}; -+ -+&lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <4>; -+}; -+ -+&lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <5>; -+}; -+ -+&lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <6>; -+}; -+ -+&lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <7>; -+}; -+ -+&lpc1_ibt { -+ status = "okay"; -+}; -+ -+&lpc1_mbox { -+ status = "okay"; -+}; -+ -+#if 1 -+&lpc1_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+#else -+&lpc1_pcc { -+ status = "okay"; -+ pcc-ports = <0x80>; -+}; -+#endif -+ -+&lpc1_uart_routing { -+ status = "okay"; -+}; -+ -+&video0 { -+ status = "okay"; -+ memory-region = <&video_engine_memory0>; -+}; -+ -+&video1 { -+ status = "okay"; -+ memory-region = <&video_engine_memory1>; -+}; -+ -+&disp_intf { -+ status = "okay"; -+}; -+ -+&rtc { -+ status = "okay"; -+}; -+ -+&rsss { -+ status = "okay"; -+}; -+ -+&ecdsa { -+ status = "okay"; -+}; -+ -+&hace { -+ status = "okay"; -+}; -+ -+#if PCIE0_EP -+&bmc_dev0 { -+ status = "okay"; -+ memory-region = <&bmc_dev0_memory>; -+}; -+ -+&xdma0 { -+ status = "okay"; -+ memory-region = <&xdma_memory0>; -+}; -+ -+&pcie_vuart0 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_vuart1 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <8>; -+}; -+ -+&pcie_lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <9>; -+}; -+ -+&pcie_lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <10>; -+}; -+ -+&pcie_lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <11>; -+}; -+ -+&pcie_lpc0_ibt { -+ status = "okay"; -+ bt-channel = <2>; -+}; -+ -+&pcie0_mmbi0 { -+ status = "okay"; -+ memory-region = <&pcie0_mmbi0_memory>; -+ -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; -+}; -+#else /* !PCIE0_EP */ -+&pcie0 { -+ status = "okay"; -+}; -+#endif /* PCIE0_EP */ -+ -+#if PCIE1_EP -+&bmc_dev1 { -+ status = "okay"; -+ memory-region = <&bmc_dev1_memory>; -+}; -+ -+&xdma1 { -+ status = "okay"; -+ memory-region = <&xdma_memory1>; -+}; -+ -+&pcie_vuart2 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_vuart3 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; -+ -+&pcie_lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <12>; -+}; -+ -+&pcie_lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <13>; -+}; -+ -+&pcie_lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <14>; -+}; -+ -+&pcie_lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <15>; -+}; -+ -+&pcie_lpc1_ibt { -+ status = "okay"; -+ bt-channel = <3>; -+}; -+ -+&pcie1_mmbi4 { -+ status = "okay"; -+ memory-region = <&pcie1_mmbi4_memory>; -+ -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; -+}; -+#else /* !PCIE1_EP */ -+&pcie1 { -+ status = "okay"; -+}; -+#endif /* PCIE1_EP */ -+ -+&sdio_controller { -+ status = "okay"; -+ mmc-hs200-1_8v; -+ -+ vcc_sdhci0: regulator-vcc-sdhci0 { -+ compatible = "regulator-fixed"; -+ regulator-name = "SDHCI0 Vcc"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ gpios = <&gpio1 ASPEED_GPIO(G, 6) GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ -+ vccq_sdhci0: regulator-vccq-sdhci0 { -+ compatible = "regulator-gpio"; -+ regulator-name = "SDHCI0 VccQ"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ gpios = <&gpio1 ASPEED_GPIO(G, 7) GPIO_ACTIVE_HIGH>; -+ gpios-states = <1>; -+ states = <3300000 1>, -+ <1800000 0>; -+ }; -+}; -+ -+&sdhci { -+ status = "okay"; -+ bus-width = <4>; -+ max-frequency = <125000000>; -+ /* DDR50 bits in CAPA2 are not supported */ -+ sdhci-caps-mask = <0x6 0x0>; -+ sdhci-drive-type = /bits/ 8 <3>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_sd_default>; -+ vmmc-supply = <&vcc_sdhci0>; -+ vqmmc-supply = <&vccq_sdhci0>; -+ sd-uhs-sdr104; /* enable sdr104 to execute tuning */ -+}; -+ -+#if 1 -+&i2c0 { -+ status = "okay"; -+}; -+ -+&i2c1 { -+ status = "okay"; -+}; -+ -+&i2c2 { -+ status = "okay"; -+}; -+ -+&i2c3 { -+ status = "okay"; -+}; -+ -+&i2c4 { -+ status = "okay"; -+}; -+ -+&i2c5 { -+ status = "okay"; -+}; -+ -+&i2c6 { -+ status = "okay"; -+}; -+ -+&i2c7 { -+ status = "okay"; -+}; -+ -+&i2c8 { -+ status = "okay"; -+}; -+ -+&i2c11 { -+ status = "okay"; -+}; -+ -+&i2c12 { -+ status = "okay"; -+}; -+ -+&i2c13 { -+ status = "okay"; -+}; -+#endif -+ -+#if 0 -+&ehci0 { -+ status = "okay"; -+}; -+ -+&ehci1 { -+ status = "okay"; -+}; -+ -+&uhci0 { -+ status = "okay"; -+ memory-region = <&uhci0_reserved>; -+}; -+ -+#endif -+ -+#if 1 -+&uphy3a { -+ status = "okay"; -+}; -+ -+&uphy3b { -+ status = "okay"; -+}; -+#endif -+ -+#if 0 -+&xhci0 { -+ status = "okay"; -+}; -+ -+&xhci1 { -+ status = "okay"; -+}; -+#endif -+ -+&vhuba0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; -+}; -+ -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; -+ -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ -+&vhubb1 { -+ status = "okay"; -+}; -+ -+&vhubc { -+ status = "okay"; -+#if 0 -+ pinctrl-0 = <&pinctrl_usb2cud_default>; -+ aspeed,uart-ports = <12>; -+#endif -+}; -+ -+&ehci3 { -+ status = "okay"; -+}; -+ -+&uhci1 { -+ status = "okay"; -+ memory-region = <&uhci1_reserved>; -+}; -+ -+&wdt0 { -+ status = "okay"; -+}; -+ -+&wdt1 { -+ status = "okay"; -+}; -+ -+&otp { -+ status = "okay"; -+}; -+ -+#if 0 -+&soc0 { -+ mbox-ssp-0 { -+ compatible = "aspeed,aspeed-mbox"; -+ reg = <0x4 0x31480000 0x0 0x200000>, <0x0 0x10001000 0x0 0x1000>; -+ mboxes = <&mbox0 0>; -+ aspeed,tx-timeout = <100>; -+ }; -+}; -+#endif -+ -+#if 1 -+&soc0 { -+ mbox-bootmcu-1 { -+ compatible = "aspeed,aspeed-mbox"; -+ reg = <0x4 0x31880000 0x0 0x100000>, <0x4 0x31980000 0x0 0x100000>; -+ mboxes = <&mbox2 1>; -+ aspeed,tx-timeout = <10000>; -+ }; -+}; -+#endif -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts -new file mode 100644 -index 000000000..9d36a15e3 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-ncsi.dts -@@ -0,0 +1,48 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-evb.dts" -+ -+/ { -+ model = "AST2700A1-NCSI"; -+}; -+ -+&sgpios { -+ status = "disabled"; -+}; -+ -+&mac0 { -+ status = "okay"; -+ -+ phy-mode = "rmii"; -+ use-ncsi; -+ -+ pinctrl-names = "default"; -+ /* If you want to use RMII0 RCLKO as internal clock for RMII, -+ * add &pinctrl_rmii0_rclko_default in pinctrl-0. -+ */ -+ pinctrl-0 = <&pinctrl_rmii0_default>; -+}; -+ -+&mac1 { -+ status = "okay"; -+ -+ phy-mode = "rmii"; -+ use-ncsi; -+ -+ pinctrl-names = "default"; -+ /* If you want to use RMII1 RCLKO as internal clock for RMII, -+ * add &pinctrl_rmii1_rclko_default in pinctrl-0. -+ */ -+ pinctrl-0 = <&pinctrl_rmii1_default>; -+}; -+ -+&syscon1 { -+ mac0-clk-delay = <0 0 -+ 0 0 -+ 0 0>; -+ mac1-clk-delay = <0 0 -+ 0 0 -+ 0 0>; -+}; -diff --git a/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts b/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts -new file mode 100644 -index 000000000..0e89e2bc1 ---- /dev/null -+++ b/arch/arm64/boot/dts/aspeed/ast2700a1-raw.dts -@@ -0,0 +1,220 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+/dts-v1/; -+ -+#include "ast2700a1-evb.dts" -+ -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "bmc"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+#include "aspeed-evb-flash-layout-128.dtsi" -+ }; -+ -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; -+ -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; -+ -+&spi1 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; -+ pinctrl-names = "default"; -+ -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+ -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi1:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; -+ -+&spi2 { -+ status = "disabled"; -+}; -+ -+&emmc_controller { -+ status = "disabled"; -+}; -+ -+&emmc { -+ status = "disabled"; -+}; -+ -+&ufs_controller { -+ status = "disabled"; -+}; -+ -+&ufs { -+ status = "disabled"; -+}; -+ -+&video0 { -+ status = "disabled"; -+}; -+ -+&video1 { -+ status = "disabled"; -+}; -+ -+&disp_intf { -+ status = "disabled"; -+}; -+ -+#if PCIE0_EP -+&bmc_dev0 { -+ status = "disabled"; -+}; -+ -+&xdma0 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart0 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs0 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs2 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_kcs3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc0_ibt { -+ status = "disabled"; -+}; -+ -+&pcie0_mmbi0 { -+ status = "disabled"; -+}; -+#else -+&pcie0 { -+ status = "disabled"; -+}; -+#endif -+ -+#if PCIE1_EP -+&bmc_dev1 { -+ status = "disabled"; -+}; -+ -+&xdma1 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart2 { -+ status = "disabled"; -+}; -+ -+&pcie_vuart3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs0 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs1 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs2 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_kcs3 { -+ status = "disabled"; -+}; -+ -+&pcie_lpc1_ibt { -+ status = "disabled"; -+}; -+ -+&pcie1_mmbi4 { -+ status = "disabled"; -+}; -+#else -+&pcie1 { -+ status = "disabled"; -+}; -+#endif -+ -+&sdio_controller { -+ status = "disabled"; -+}; -+ -+&sdhci { -+ status = "disabled"; -+}; -+ -diff --git a/crypto/Makefile b/crypto/Makefile -index 4c99e5d37..625618d88 100644 ---- a/crypto/Makefile -+++ b/crypto/Makefile -@@ -181,6 +181,7 @@ obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o - obj-$(CONFIG_CRYPTO_ECC) += ecc.o - obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o - obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o -+obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed_crypt.o - - ecdh_generic-y += ecdh.o - ecdh_generic-y += ecdh_helper.o -diff --git a/crypto/aspeed_crypt.c b/crypto/aspeed_crypt.c -new file mode 100644 -index 000000000..a6f8d6d9d ---- /dev/null -+++ b/crypto/aspeed_crypt.c -@@ -0,0 +1,264 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2025 Aspeed Technology Inc. -+ */ -+ -+#define ASPEED_CRYPT_NAME "aspeed-crypt" -+#define pr_fmt(fmt) ASPEED_CRYPT_NAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "internal.h" -+ -+enum aspeed_crypt_type { -+ ASPEED_SKCIPHER_TYPE, -+ ASPEED_AHASH_TYPE, -+ ASPEED_AKCIPHER_TYPE, -+ ASPEED_SIG_TYPE, -+}; -+ -+struct aspeed_crypt_drv { -+ char *algo; -+ char *drv_name; -+}; -+ -+struct aspeed_crypt_test { -+ char *test_item; -+ enum aspeed_crypt_type type; -+ int num; -+ struct aspeed_crypt_drv *algo; -+}; -+ -+struct aspeed_crypt_drv aspeed_des_binding[] = { -+ { "ecb(des)", "aspeed-ecb-des" }, -+ { "cbc(des)", "aspeed-cbc-des" }, -+ { "ctr(des)", "aspeed-ctr-des" }, -+}; -+ -+struct aspeed_crypt_drv aspeed_tdes_binding[] = { -+ { "ecb(des3_ede)", "aspeed-ecb-tdes" }, -+ { "cbc(des3_ede)", "aspeed-cbc-tdes" }, -+ { "ctr(des3_ede)", "aspeed-ctr-tdes" }, -+}; -+ -+struct aspeed_crypt_drv aspeed_sha3_binding[] = { -+ { "sha3-224", "aspeed-sha3-224" }, -+ { "sha3-256", "aspeed-sha3-256" }, -+ { "sha3-384", "aspeed-sha3-384" }, -+ { "sha3-512", "aspeed-sha3-512" }, -+}; -+ -+struct aspeed_crypt_drv aspeed_rsa_binding[] = { -+ { "rsa", "aspeed-rsa" }, -+}; -+ -+struct aspeed_crypt_drv aspeed_ecdsa_binding[] = { -+ { "ecdsa-nist-p256", "aspeed-ecdsa-nist-p256" }, -+ { "ecdsa-nist-p384", "aspeed-ecdsa-nist-p384" }, -+}; -+ -+static bool aspeed_detect_skcipher_drv(char *drv_name) -+{ -+ struct crypto_skcipher *tfm = NULL; -+ bool found = false; -+ -+ tfm = crypto_alloc_skcipher(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_skcipher(tfm); -+ } -+ -+ return found; -+} -+ -+static bool aspeed_detect_ahash_drv(char *drv_name) -+{ -+ struct crypto_ahash *tfm = NULL; -+ bool found = false; -+ -+ tfm = crypto_alloc_ahash(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_ahash(tfm); -+ } -+ -+ return found; -+} -+ -+static bool aspeed_detect_akcipher_drv(char *drv_name) -+{ -+ struct crypto_akcipher *tfm = NULL; -+ bool found = false; -+ -+ tfm = crypto_alloc_akcipher(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_akcipher(tfm); -+ } -+ -+ return found; -+} -+ -+static bool aspeed_detect_sig_drv(char *drv_name) -+{ -+ struct crypto_sig *tfm = NULL; -+ bool found = false; -+ -+ tfm = crypto_alloc_sig(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_sig(tfm); -+ } -+ -+ return found; -+} -+ -+static bool aspeed_detect_drv(enum aspeed_crypt_type type, char *drv_name) -+{ -+ switch (type) { -+ case ASPEED_SKCIPHER_TYPE: -+ return aspeed_detect_skcipher_drv(drv_name); -+ case ASPEED_AHASH_TYPE: -+ return aspeed_detect_ahash_drv(drv_name); -+ case ASPEED_AKCIPHER_TYPE: -+ return aspeed_detect_akcipher_drv(drv_name); -+ case ASPEED_SIG_TYPE: -+ return aspeed_detect_sig_drv(drv_name); -+ default: -+ return false; -+ } -+} -+ -+static const struct aspeed_crypt_test * -+aspeed_crypt_get_alg(const char *algo_name) -+{ -+ int i = 0; -+ static const struct aspeed_crypt_test algo_ts[] = { -+ { "des", ASPEED_SKCIPHER_TYPE, ARRAY_SIZE(aspeed_des_binding), -+ aspeed_des_binding }, -+ { "des3", ASPEED_SKCIPHER_TYPE, ARRAY_SIZE(aspeed_tdes_binding), -+ aspeed_tdes_binding }, -+ { "sha-3", ASPEED_AHASH_TYPE, ARRAY_SIZE(aspeed_sha3_binding), -+ aspeed_sha3_binding }, -+ { "rsa", ASPEED_AKCIPHER_TYPE, ARRAY_SIZE(aspeed_rsa_binding), -+ aspeed_rsa_binding }, -+ { "ecdsa", ASPEED_SIG_TYPE, ARRAY_SIZE(aspeed_ecdsa_binding), -+ aspeed_ecdsa_binding }, -+ }; -+ -+ for (i = 0; i < ARRAY_SIZE(algo_ts); i++) { -+ if (strlen(algo_ts[i].test_item) == strlen(algo_name) && -+ strncmp(algo_ts[i].test_item, algo_name, -+ strlen(algo_name)) == 0) -+ return &algo_ts[i]; -+ } -+ -+ return NULL; -+} -+ -+static __maybe_unused int aspeed_crypt_run_tests(char *alg_name) -+{ -+ const struct aspeed_crypt_test *ts; -+ int ret = 0; -+ int i = 0; -+ -+ ts = aspeed_crypt_get_alg(alg_name); -+ if (!ts) { -+ pr_err("No test suite found for algorithm: %s", alg_name); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < ts->num && ret == 0; i++) { -+ if (aspeed_detect_drv(ts->type, ts->algo[i].drv_name)) -+ ret = alg_test(ts->algo[i].drv_name, ts->algo[i].algo, -+ 0, 0); -+ else -+ ret = -ENOENT; -+ -+ pr_info("alg: %s tests %s\n", ts->algo[i].algo, -+ !ret ? "passed" : "failed"); -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && \ -+ !defined(CONFIG_CRYPTO_DEV_ASPEED_ACRY) -+static ssize_t aspeed_crypt_write(struct file *file, const char __user *ubuf, -+ size_t count, loff_t *ppos) -+{ -+ pr_err("Crypto tests are disabled\n"); -+ return -EOPNOTSUPP; -+} -+#else -+static ssize_t aspeed_crypt_write(struct file *file, const char __user *ubuf, -+ size_t count, loff_t *ppos) -+{ -+ u8 kbuf[16] = { 0 }; -+ -+ if (count > sizeof(kbuf) - 1) -+ return -EINVAL; -+ -+ if (copy_from_user(kbuf, ubuf, min(count, sizeof(kbuf)))) -+ return -EFAULT; -+ strim(kbuf); -+ -+ if (!aspeed_crypt_run_tests(kbuf)) -+ pr_err("alg: %s tests passed\n", kbuf); -+ else -+ pr_err("alg: %s tests failed\n", kbuf); -+ -+ return min(count, sizeof(kbuf)); -+} -+#endif -+ -+static const struct file_operations fops = { -+ .owner = THIS_MODULE, -+ .write = aspeed_crypt_write, -+}; -+ -+static dev_t dev; -+static struct cdev cdev; -+static struct class *class; -+static int __init acrypt_mod_init(void) -+{ -+ int ret; -+ -+ ret = alloc_chrdev_region(&dev, 0, 1, ASPEED_CRYPT_NAME); -+ if (ret < 0) -+ return ret; -+ -+ cdev_init(&cdev, &fops); -+ ret = cdev_add(&cdev, dev, 1); -+ if (ret) -+ goto del_region; -+ -+ class = class_create(ASPEED_CRYPT_NAME); -+ if (IS_ERR(class)) { -+ ret = PTR_ERR(class); -+ goto del_cdev; -+ } -+ -+ device_create(class, NULL, dev, NULL, ASPEED_CRYPT_NAME); -+ return 0; -+del_cdev: -+ cdev_del(&cdev); -+del_region: -+ unregister_chrdev_region(dev, 1); -+ return ret; -+} -+ -+static void __exit acrypt_mod_fini(void) -+{ -+ device_destroy(class, dev); -+ class_destroy(class); -+ cdev_del(&cdev); -+ unregister_chrdev_region(dev, 1); -+} -+ -+subsys_initcall(acrypt_mod_init); -+module_exit(acrypt_mod_fini); -diff --git a/drivers/bus/aspeed-ltpi.c b/drivers/bus/aspeed-ltpi.c -index f24933549..f89e77990 100644 ---- a/drivers/bus/aspeed-ltpi.c -+++ b/drivers/bus/aspeed-ltpi.c -@@ -1,6 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - // Copyright ASPEED Technology - -+#include "linux/dev_printk.h" - #include - #include - #include -@@ -14,6 +15,10 @@ - #include - #include - #include -+#include -+#include -+ -+#include "aspeed-ltpi.h" - - #define LTPI_AUTO_CAP_LOW 0x24 - #define LTPI_I2C_IO_FRAME_EN GENMASK(29, 24) -@@ -49,17 +54,117 @@ - #define SCU_IO_OTP_TRAP2 0xa20 - #define SCU_IO_OTP_TRAP2_CLEAR 0xa24 - -+/* SCU registers for PLL control */ -+#define SCU1_HPLL_1 0x300 -+#define SCU1_HPLL_2 0x304 -+#define SCU1_APLL_1 0x310 -+#define SCU1_APLL_2 0x314 -+#define SCU1_DPLL_1 0x320 -+#define SCU1_DPLL_2 0x324 -+#define SCU1_L0PLL_1 0x340 -+#define SCU1_L0PLL_2 0x344 -+#define SCU1_L1PLL_1 0x350 -+#define SCU1_L1PLL_2 0x354 -+ -+#define PLL_REG1_RESET BIT(25) -+#define PLL_REG1_BYPASS BIT(24) -+#define PLL_REG1_DIS BIT(23) -+#define PLL_REG1_P GENMASK(22, 19) -+#define PLL_REG1_N GENMASK(18, 13) -+#define PLL_REG1_M GENMASK(12, 0) -+ -+#define PLL_REG2_LOCK BIT(31) -+#define PLL_REG2_BWADJ GENMASK(11, 0) -+ - #define MAX_I2C_IN_LTPI 6 - #define MAX_UART_IN_LTPI 2 - -+#define ADVERTISE_TIMEOUT_US 105000 /* 105 ms */ -+ - enum chip_version { - AST2700, - AST1700, - }; - -+struct ltpi_clk_info { -+ s16 freq; /* clock frequency in MHz*/ -+ s16 clk_sel; /* clock selection */ -+}; -+ -+static const struct ltpi_clk_info ltpi_clk_lookup_sdr[13] = { -+ { 25, REG_LTPI_PLL_25M }, -+ { 50, REG_LTPI_PLL_LPLL }, -+ { 75, REG_LTPI_PLL_LPLL }, -+ { 100, REG_LTPI_PLL_LPLL }, -+ { 150, REG_LTPI_PLL_LPLL }, -+ { 200, REG_LTPI_PLL_LPLL }, -+ { 250, REG_LTPI_PLL_LPLL }, -+ { 300, REG_LTPI_PLL_LPLL }, -+ { 400, REG_LTPI_PLL_LPLL }, -+ { 600, REG_LTPI_PLL_LPLL }, -+ { -1, -1 }, -+ { -1, -1 }, -+ { 500, REG_LTPI_PLL_LPLL } -+}; -+ -+static const struct ltpi_clk_info ltpi_clk_lookup_ddr[13] = { -+ { 50, REG_LTPI_PLL_LPLL }, -+ { 100, REG_LTPI_PLL_LPLL }, -+ { 150, REG_LTPI_PLL_LPLL }, -+ { 200, REG_LTPI_PLL_LPLL }, -+ { 300, REG_LTPI_PLL_LPLL }, -+ { 400, REG_LTPI_PLL_LPLL }, -+ { 500, REG_LTPI_PLL_LPLL }, -+ { 600, REG_LTPI_PLL_LPLL }, -+ { 800, REG_LTPI_PLL_LPLL }, -+ { 1200, REG_LTPI_PLL_LPLL }, -+ { -1, -1 }, -+ { -1, -1 }, -+ { 1000, REG_LTPI_PLL_LPLL } -+}; -+ -+#define MHZ(x) ((x) * 1000000) -+#define NUM_PLL_PARAM 13 -+#define REG_N_M_P(n, m, p) ((((n) - 1) << 13) | ((m) - 1) | (((p) - 1) << 19)) -+#define REG_BWADJ(bwadj) ((bwadj) - 1) -+ -+struct pll_param { -+ int freq; -+ u32 n_m_p; -+ u16 bwadj; -+}; -+ -+static const struct pll_param pll_param_lookup[NUM_PLL_PARAM] = { -+ { .freq = MHZ(50), .n_m_p = REG_N_M_P(1, 32, 16), .bwadj = REG_BWADJ(16) }, -+ { .freq = MHZ(75), .n_m_p = REG_N_M_P(1, 48, 16), .bwadj = REG_BWADJ(24) }, -+ { .freq = MHZ(100), .n_m_p = REG_N_M_P(1, 56, 14), .bwadj = REG_BWADJ(28) }, -+ { .freq = MHZ(150), .n_m_p = REG_N_M_P(1, 60, 10), .bwadj = REG_BWADJ(30) }, -+ { .freq = MHZ(200), .n_m_p = REG_N_M_P(1, 48, 6), .bwadj = REG_BWADJ(24) }, -+ { .freq = MHZ(250), .n_m_p = REG_N_M_P(1, 60, 6), .bwadj = REG_BWADJ(30) }, -+ { .freq = MHZ(300), .n_m_p = REG_N_M_P(1, 48, 4), .bwadj = REG_BWADJ(24) }, -+ { .freq = MHZ(400), .n_m_p = REG_N_M_P(1, 32, 2), .bwadj = REG_BWADJ(16) }, -+ { .freq = MHZ(500), .n_m_p = REG_N_M_P(1, 40, 2), .bwadj = REG_BWADJ(20) }, -+ { .freq = MHZ(600), .n_m_p = REG_N_M_P(1, 48, 2), .bwadj = REG_BWADJ(24) }, -+ { .freq = MHZ(800), .n_m_p = REG_N_M_P(1, 32, 1), .bwadj = REG_BWADJ(16) }, -+ { .freq = MHZ(1000), .n_m_p = REG_N_M_P(1, 40, 1), .bwadj = REG_BWADJ(20) }, -+ { .freq = MHZ(1200), .n_m_p = REG_N_M_P(1, 48, 1), .bwadj = REG_BWADJ(24) }, -+}; -+ -+struct pll_info { -+ u32 reg_offset0; -+ u32 reg_offset1; -+}; -+ -+static const struct pll_info scu_pll_info[] = { -+ [0] = { .reg_offset0 = SCU1_L0PLL_1, .reg_offset1 = SCU1_L0PLL_2 }, -+ [1] = { .reg_offset0 = SCU1_L1PLL_1, .reg_offset1 = SCU1_L1PLL_2 }, -+}; -+ - struct aspeed_ltpi_priv { - struct device *dev; - void __iomem *regs; -+ void __iomem *phy_regs; -+ void __iomem *top_regs; - struct clk *ltpi_clk; - struct clk *ltpi_phyclk; - struct reset_control *ltpi_rst; -@@ -69,8 +174,28 @@ struct aspeed_ltpi_priv { - u32 i2c_timing_0; - u32 i2c_timing_1; - u32 uart_tunneling; -+ int index; -+ -+ /* Training parameters */ -+ u16 phy_speed_cap; -+ bool otp_ddr_dis; -+ int disable_auto_downshift; -+ int crc_format; -+ int io_driving; -+ int clk_inverse; -+ int link_speed_frm_rx_cnt; -+ int ad_timeout; -+ u64 op_timeout; -+ u64 t_link_detect; - }; - -+static int ltpi_get_link_partner(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 reg = readl(ltpi->regs + LTPI_LINK_MNG_ST); -+ -+ return FIELD_GET(REG_LTPI_LINK_PARTNER_FLAG, reg); -+} -+ - static irqreturn_t aspeed_ltpi_irq_handler(int irq, void *dev_id) - { - struct aspeed_ltpi_priv *priv = dev_id; -@@ -79,8 +204,11 @@ static irqreturn_t aspeed_ltpi_irq_handler(int irq, void *dev_id) - if (status & LTPI_INTR_EN_OP_LINK_LOST) { - writel(0, priv->regs + LTPI_INTR_EN); - writel(status, priv->regs + LTPI_INTR_STATUS); -- panic("LTPI link lost!\n"); -+ if (ltpi_get_link_partner(priv)) -+ panic("LTPI link lost!\n"); - /* Will not return */ -+ else -+ dev_err(priv->dev, "LTPI link lost!\n"); - } - - writel(status, priv->regs + LTPI_INTR_STATUS); -@@ -122,9 +250,11 @@ static int aspeed_ltpi_init_mux(struct aspeed_ltpi_priv *priv) - for (i = 0; i < MAX_I2C_IN_LTPI; i++) { - if ((priv->i2c_tunneling >> i) & 0x1) { - writel(priv->i2c_timing_0, -- priv->regs + LTPI_I2C_TIMING_0 + (0x8 * i)); -+ priv->regs + LTPI_I2C_TIMING_0 + -+ (0x8 * i)); - writel(priv->i2c_timing_1, -- priv->regs + LTPI_I2C_TIMING_1 + (0x8 * i)); -+ priv->regs + LTPI_I2C_TIMING_1 + -+ (0x8 * i)); - } - } - } -@@ -132,6 +262,717 @@ static int aspeed_ltpi_init_mux(struct aspeed_ltpi_priv *priv) - return 0; - } - -+static int clz16(u16 x) -+{ -+ int n = 0; -+ -+ if (x == 0) -+ return 16; -+ -+ if (x <= 0x00ff) { -+ n += 8; -+ x <<= 8; -+ } -+ if (x <= 0x0fff) { -+ n += 4; -+ x <<= 4; -+ } -+ if (x <= 0x3fff) { -+ n += 2; -+ x <<= 2; -+ } -+ if (x <= 0x7fff) -+ n += 1; -+ -+ return n; -+} -+ -+static u16 find_max_speed(u16 cap) -+{ -+ return 15 - clz16(cap & ~LTPI_SP_CAP_DDR); -+} -+ -+static void ltpi_phy_unlock(struct aspeed_ltpi_priv *ltpi) -+{ -+ writel(LTPI_PROT_KEY_UNLOCK, ltpi->phy_regs + LTPI_PROT_KEY); -+} -+ -+static void ltpi_enable_rx_bias(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 val = readl(ltpi->top_regs + LTPI_LVDS_RX_CTRL); -+ -+ val |= (REG_LTPI_LVDS_RX1_BIAS_EN | REG_LTPI_LVDS_RX0_BIAS_EN); -+ writel(val, ltpi->top_regs + LTPI_LVDS_RX_CTRL); -+ udelay(1); -+} -+ -+static int ltpi_phy_get_mode(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 reg = readl(ltpi->phy_regs + LTPI_PHY_CTRL); -+ -+ return FIELD_GET(REG_LTPI_PHY_MODE, reg); -+} -+ -+static int ltpi_phy_set_mode(struct aspeed_ltpi_priv *ltpi, int mode) -+{ -+ u32 reg; -+ -+ if (mode < 0 || mode > LTPI_PHY_MODE_CDR_HI_SP) { -+ dev_err(ltpi->dev, "%s: invalid mode %d\n", __func__, mode); -+ return -1; -+ } -+ -+ reg = readl(ltpi->phy_regs + LTPI_PHY_CTRL); -+ reg &= ~REG_LTPI_PHY_MODE; -+ reg |= mode; -+ writel(reg, ltpi->phy_regs + LTPI_PHY_CTRL); -+ -+ return 0; -+} -+ -+static int ltpi_phy_set_clksel(struct aspeed_ltpi_priv *ltpi, int clksel, -+ bool is_op_clk) -+{ -+ u32 reg; -+ -+#define RX_CLK_INVERSE BIT(1) -+#define TX_CLK_INVERSE BIT(0) -+ -+ reg = readl(ltpi->phy_regs + LTPI_PLL_CTRL); -+ reg &= ~(REG_LTPI_PLL_SELECT | REG_LTPI_PLL_SET | -+ REG_LTPI_RX_PHY_CLK_INV | REG_LTPI_TX_PHY_CLK_INV); -+ reg |= FIELD_PREP(REG_LTPI_PLL_SELECT, clksel); -+ -+ if (ltpi->clk_inverse & RX_CLK_INVERSE) -+ reg |= REG_LTPI_RX_PHY_CLK_INV; -+ -+ if (ltpi->clk_inverse & TX_CLK_INVERSE) -+ reg |= REG_LTPI_TX_PHY_CLK_INV; -+ -+ if (is_op_clk) -+ reg |= REG_LTPI_PLL_SET; -+ -+ writel(reg, ltpi->phy_regs + LTPI_PLL_CTRL); -+ -+ return 0; -+} -+ -+static void ltpi_set_crc_format(struct aspeed_ltpi_priv *ltpi, int crc_fmt) -+{ -+ u32 val = readl(ltpi->regs + LTPI_CRC_OPTION); -+ -+ val &= ~(REG_LTPI_SW_CRC_OUT_ML_FIRST | REG_LTPI_SW_CRC_IN_LSB_FIRST); -+ if (crc_fmt) -+ val |= REG_LTPI_SW_CRC_OUT_ML_FIRST | -+ REG_LTPI_SW_CRC_IN_LSB_FIRST; -+ -+ writel(val, ltpi->regs + LTPI_CRC_OPTION); -+} -+ -+static int ltpi_reset(struct aspeed_ltpi_priv *ltpi) -+{ -+ /* Using reset controller */ -+ reset_control_assert(ltpi->ltpi_rst); -+ udelay(1); -+ /* Assuming clk gate is handled by clock framework or enabled */ -+ /* U-Boot does ungate here */ -+ if (ltpi->ltpi_clk) -+ clk_prepare_enable(ltpi->ltpi_clk); -+ -+ reset_control_deassert(ltpi->ltpi_rst); -+ -+ ltpi_phy_unlock(ltpi); -+ -+ return 0; -+} -+ -+static u32 ltpi_get_link_mng_state(struct aspeed_ltpi_priv *ltpi) -+{ -+ return FIELD_GET(REG_LTPI_LINK_MNG_ST, -+ readl(ltpi->regs + LTPI_LINK_MNG_ST)); -+} -+ -+static int ltpi_poll_link_mng_state(struct aspeed_ltpi_priv *ltpi, -+ u32 expected, u32 unexpected, -+ int timeout_us) -+{ -+ u32 state; -+ int ret; -+ -+ ret = readl_poll_timeout(ltpi->regs + LTPI_LINK_MNG_ST, state, -+ (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == expected) || -+ (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == unexpected), -+ 100, timeout_us); -+ -+ if (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == unexpected) -+ return -ENOLINK; -+ -+ if (ret) -+ return -ETIMEDOUT; -+ -+ return 0; -+} -+ -+static int ltpi_wait_state_pll_set(struct aspeed_ltpi_priv *ltpi, -+ int timeout_us) -+{ -+ return ltpi_poll_link_mng_state(ltpi, LTPI_LINK_MNG_ST_WAIT_PLL_SET, -1, -+ timeout_us); -+} -+ -+static int ltpi_wait_state_op(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 val = readl(ltpi->regs + LTPI_LINK_ST); -+ -+ val |= (REG_LTPI_CON_ACC_TO_ERR | REG_LTPI_FRM_CRC_ERR | -+ REG_LTPI_LINK_LOST_ERR); -+ writel(val, ltpi->regs + LTPI_LINK_ST); -+ -+ return ltpi_poll_link_mng_state(ltpi, LTPI_LINK_MNG_ST_OP, -+ LTPI_LINK_MNG_ST_DETECT_ALIGN, -+ ltpi->ad_timeout); -+} -+ -+static int ltpi_set_lvds_io_driving(struct aspeed_ltpi_priv *ltpi, int driving) -+{ -+ u32 val; -+ -+ val = readl(ltpi->top_regs + LTPI_SW_FORCE_EN); -+ val |= REG_LTPI_SW_FORCE_LVDS_TX_DS_EN; -+ writel(val, ltpi->top_regs + LTPI_SW_FORCE_EN); -+ -+ val = readl(ltpi->top_regs + LTPI_LVDS_TX_CTRL); -+ val &= ~(REG_LTPI_LVDS_TX1_DS1 | REG_LTPI_LVDS_TX1_DS0 | -+ REG_LTPI_LVDS_TX0_DS1 | REG_LTPI_LVDS_TX0_DS0); -+ -+ /* tx1: clk, tx0: data */ -+ if (driving & BIT(1)) -+ val |= (REG_LTPI_LVDS_TX1_DS1 | REG_LTPI_LVDS_TX0_DS1); -+ -+ if (driving & BIT(0)) -+ val |= (REG_LTPI_LVDS_TX1_DS0 | REG_LTPI_LVDS_TX0_DS0); -+ -+ writel(val, ltpi->top_regs + LTPI_LVDS_TX_CTRL); -+ -+ return 0; -+} -+ -+static int ltpi_set_local_speed_cap(struct aspeed_ltpi_priv *ltpi, -+ u32 speed_cap) -+{ -+ u32 reg; -+ -+ /* only set bits that Aspeed SOC supported */ -+ speed_cap &= LTPI_SP_CAP_ASPEED_SUPPORTED; -+ if (ltpi->otp_ddr_dis) -+ speed_cap &= ~LTPI_SP_CAP_DDR; -+ -+ reg = readl(ltpi->regs + LTPI_CAP_LOCAL); -+ reg &= ~REG_LTPI_SP_CAP_LOCAL; -+ reg |= FIELD_PREP(REG_LTPI_SP_CAP_LOCAL, speed_cap); -+ writel(reg, ltpi->regs + LTPI_CAP_LOCAL); -+ -+ return 0; -+} -+ -+static void ltpi_do_link_training(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 val; -+ -+ /* Reset the PHY to PHY_MODE_OFF */ -+ ltpi_reset(ltpi); -+ -+ ltpi_enable_rx_bias(ltpi); -+ ltpi_set_local_speed_cap(ltpi, ltpi->phy_speed_cap); -+ ltpi_set_lvds_io_driving(ltpi, ltpi->io_driving); -+ ltpi_set_crc_format(ltpi, ltpi->crc_format); -+ -+ /* -+ * Configure the LINK_SPEED frame count to be received before -+ * entering AD. This configuraiton only effects the SCM LTPI. -+ */ -+ val = readl(ltpi->regs + LTPI_LINK_MANAGE_CTRL0); -+ val &= ~REG_LTPI_RX_LINK_SP_FRM_NUM; -+ val |= FIELD_PREP(REG_LTPI_RX_LINK_SP_FRM_NUM, -+ ltpi->link_speed_frm_rx_cnt); -+ writel(val, ltpi->regs + LTPI_LINK_MANAGE_CTRL0); -+ -+ /* -+ * ad_timeout in us = ad_timeout in clock cycles * period of 25MHz -+ * ad_timeout in clock cycles -+ * = ad_timeout in us / period of 25MHz -+ * = (ad_timeout in us * 1000)ns / 40ns = ad_timeout * 25 -+ */ -+ writel(ltpi->ad_timeout * 25, ltpi->regs + LTPI_LINK_MANAGE_CTRL1); -+ -+ /* Set the clock source to the base frequency 25MHz */ -+ ltpi_phy_set_clksel(ltpi, REG_LTPI_PLL_25M, false); -+ -+ /* To make the remote side back to the link lost state */ -+ mdelay(ADVERTISE_TIMEOUT_US / 1000); -+ -+ ltpi_phy_set_mode(ltpi, LTPI_PHY_MODE_SDR); -+} -+ -+static int scu_get_pll_freq(struct aspeed_ltpi_priv *ltpi, int pll_id) -+{ -+ const struct pll_info *info; -+ u32 reg; -+ int m, n, p; -+ -+ if (pll_id > 1) -+ return -1; -+ -+ info = &scu_pll_info[pll_id]; -+ regmap_read(ltpi->scu, info->reg_offset0, ®); -+ m = FIELD_GET(PLL_REG1_M, reg); -+ n = FIELD_GET(PLL_REG1_N, reg); -+ p = FIELD_GET(PLL_REG1_P, reg); -+ -+ return (25000000 * (m + 1) / (n + 1) / (p + 1)); -+} -+ -+static int scu_set_pll_freq(struct aspeed_ltpi_priv *ltpi, int pll_id, int freq) -+{ -+ const struct pll_info *info; -+ const struct pll_param *param; -+ int curr_freq, i; -+ bool match = false; -+ -+ if (pll_id > 1) -+ return -EINVAL; -+ -+ curr_freq = scu_get_pll_freq(ltpi, pll_id); -+ if (curr_freq == freq) -+ return 0; -+ -+ for (i = 0; i < NUM_PLL_PARAM; i++) { -+ if (freq == pll_param_lookup[i].freq) { -+ match = true; -+ break; -+ } -+ } -+ -+ if (!match) -+ return -EINVAL; -+ -+ param = &pll_param_lookup[i]; -+ info = &scu_pll_info[pll_id]; -+ -+ dev_info(ltpi->dev, "Setting PLL frequency to %d MHz\n", -+ freq / 1000000); -+ regmap_update_bits(ltpi->scu, info->reg_offset0, PLL_REG1_RESET, -+ PLL_REG1_RESET); -+ regmap_update_bits(ltpi->scu, info->reg_offset0, -+ PLL_REG1_P | PLL_REG1_N | PLL_REG1_M, param->n_m_p); -+ regmap_update_bits(ltpi->scu, info->reg_offset1, PLL_REG2_BWADJ, -+ param->bwadj); -+ -+ udelay(5); -+ regmap_update_bits(ltpi->scu, info->reg_offset0, PLL_REG1_RESET, 0); -+ udelay(20); -+ -+ return 0; -+} -+ -+static int ltpi_set_operational_clk(struct aspeed_ltpi_priv *ltpi, -+ u16 speed_cap) -+{ -+ const struct ltpi_clk_info *info; -+ int target_speed, clksel, phy_mode, pll_id; -+ -+ pll_id = ltpi->index; /* 0 or 1 maps to L0PLL or L1PLL in array */ -+ -+ /* find max attainable speed */ -+ target_speed = find_max_speed(speed_cap); -+ -+ /* set phy mode "OFF" */ -+ ltpi_phy_set_mode(ltpi, LTPI_PHY_MODE_OFF); -+ -+ if (speed_cap & LTPI_SP_CAP_DDR) { -+ phy_mode = LTPI_PHY_MODE_DDR; -+ info = ltpi_clk_lookup_ddr; -+ } else { -+ phy_mode = LTPI_PHY_MODE_SDR; -+ info = ltpi_clk_lookup_sdr; -+ } -+ clksel = info[target_speed].clk_sel; -+ ltpi_phy_set_clksel(ltpi, clksel, true); -+ if (clksel == REG_LTPI_PLL_LPLL) -+ scu_set_pll_freq(ltpi, pll_id, -+ info[target_speed].freq * 1000000); -+ -+ /* Start TX with the operational frequency */ -+ ltpi_phy_set_mode(ltpi, phy_mode); -+ -+ return target_speed; -+} -+ -+static int ltpi_scm_init(struct aspeed_ltpi_priv *ltpi) -+{ -+ int ret, target_speed; -+ u32 reg, state; -+ -+ dev_info(ltpi->dev, "Starting LTPI initialization\n"); -+ /* Check whether LTPI is initialized */ -+ state = ltpi_get_link_mng_state(ltpi); -+ if (state == LTPI_LINK_MNG_ST_OP) { -+ dev_info(ltpi->dev, "LTPI already operational PHY mode: %d\n", -+ ltpi_phy_get_mode(ltpi)); -+ return 0; -+ } -+ -+ ltpi->t_link_detect = ktime_get_ns(); -+ -+ /* LTPI initialization is required, start link training phase */ -+ do { -+ dev_info(ltpi->dev, "Starting LTPI link training\n"); -+ ltpi_do_link_training(ltpi); -+ do { -+ ret = ltpi_wait_state_pll_set(ltpi, 20000); -+ if (ret == 0) -+ break; -+ -+ if (ltpi->op_timeout && -+ (ktime_get_ns() - ltpi->t_link_detect > -+ ltpi->op_timeout)) { -+ dev_err(ltpi->dev, -+ "Timeout while waiting for PLL set state\n"); -+ ret = -ETIMEDOUT; -+ goto ltpi_scm_exit; -+ } -+ } while (1); -+ -+ /* read intersection of the speed capabilities */ -+ reg = FIELD_GET(REG_LTPI_SP_INTERSETION, -+ readl(ltpi->regs + LTPI_LINK_MNG_ST)); -+ if (reg == 0) { -+ dev_err(ltpi->dev, "No common speed\n"); -+ ret = -ENOLINK; -+ goto ltpi_scm_exit; -+ } -+ -+ target_speed = ltpi_set_operational_clk(ltpi, reg); -+ -+ /* poll link state 0x7 */ -+ ret = ltpi_wait_state_op(ltpi); -+ if (ret == 0) { -+ /* Start OEM TX & RX if the link partner is AST1700 */ -+ if (readl(ltpi->regs + LTPI_LINK_MNG_ST) & -+ REG_LTPI_LINK_PARTNER_FLAG) { -+ u32 val = readl(ltpi->regs + -+ LTPI_OEM_BUS_SETTING); -+ val |= (REG_LTPI_OEM_RX_START_TRIG | -+ REG_LTPI_OEM_TX_START_TRIG); -+ writel(val, ltpi->regs + LTPI_OEM_BUS_SETTING); -+ } -+ break; -+ } -+ -+ if (ltpi->op_timeout && -+ (ktime_get_ns() - ltpi->t_link_detect > ltpi->op_timeout)) { -+ dev_err(ltpi->dev, -+ "Timeout while waiting for operational state\n"); -+ ret = -ETIMEDOUT; -+ goto ltpi_scm_exit; -+ } -+ -+ if (!ltpi->disable_auto_downshift) -+ /* clear the bit to specify the current speed doesn't work */ -+ ltpi->phy_speed_cap &= ~BIT(target_speed); -+ -+ /* the lowest speed 25M should always be supported */ -+ if ((ltpi->phy_speed_cap & LTPI_SP_CAP_25M) == 0) -+ ltpi->phy_speed_cap |= LTPI_SP_CAP_25M; -+ -+ dev_warn(ltpi->dev, -+ "Failed to enter operational state, restarting link training\n"); -+ } while (1); -+ -+ dev_info(ltpi->dev, "LTPI Link trained successfully\n"); -+ return 0; -+ -+ltpi_scm_exit: -+ dev_err(ltpi->dev, "Exiting initialization\n"); -+ ltpi_reset(ltpi); -+ return ret; -+} -+ -+/* Sysfs attribute show/store functions */ -+static ssize_t ad_timeout_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", priv->ad_timeout); -+} -+ -+static ssize_t ad_timeout_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->ad_timeout = val; -+ return count; -+} -+ -+static ssize_t io_driving_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "0x%x\n", priv->io_driving); -+} -+ -+static ssize_t io_driving_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->io_driving = val; -+ return count; -+} -+ -+static ssize_t clk_inverse_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "0x%x\n", priv->clk_inverse); -+} -+ -+static ssize_t clk_inverse_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->clk_inverse = val; -+ return count; -+} -+ -+static ssize_t link_speed_frm_rx_cnt_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", priv->link_speed_frm_rx_cnt); -+} -+ -+static ssize_t link_speed_frm_rx_cnt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->link_speed_frm_rx_cnt = val; -+ return count; -+} -+ -+static ssize_t disable_auto_downshift_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", priv->disable_auto_downshift); -+} -+ -+static ssize_t disable_auto_downshift_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->disable_auto_downshift = val ? 1 : 0; -+ return count; -+} -+ -+static ssize_t crc_format_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", priv->crc_format); -+} -+ -+static ssize_t crc_format_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->crc_format = val ? 1 : 0; -+ return count; -+} -+ -+static ssize_t phy_speed_cap_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "0x%x\n", priv->phy_speed_cap); -+} -+ -+static ssize_t phy_speed_cap_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->phy_speed_cap = val; -+ return count; -+} -+ -+static ssize_t op_timeout_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%llu\n", priv->op_timeout); -+} -+ -+static ssize_t op_timeout_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned long long val; -+ -+ if (kstrtoull(buf, 0, &val)) -+ return -EINVAL; -+ -+ priv->op_timeout = val; -+ return count; -+} -+ -+static ssize_t rescan_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ u32 val, reg; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; -+ -+ if (val == 1 && priv->version == AST2700) { -+ dev_info(priv->dev, "Triggering LTPI rescan\n"); -+ if (ltpi_scm_init(priv)) { -+ dev_err(priv->dev, "LTPI rescan failed\n"); -+ return -EIO; -+ } -+ writel(LTPI_INTR_EN_OP_LINK_LOST, -+ priv->regs + LTPI_INTR_STATUS); -+ writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_EN); -+ aspeed_ltpi_init_mux(priv); -+ if (ltpi_get_link_partner(priv)) { -+ reg = FIELD_PREP(REG_LTPI_AHB_ADDR_MAP0, 0x5) | -+ FIELD_PREP(REG_LTPI_AHB_ADDR_MAP1, 0xa0); -+ } else { -+ reg = 0; -+ writel(0, priv->regs + LTPI_DATA_CH_CFG0); -+ } -+ writel(reg, priv->regs + LTPI_AHB_CTRL0); -+ } -+ -+ return count; -+} -+ -+static ssize_t link_status_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ u32 state = ltpi_get_link_mng_state(priv); -+ char state_str[128]; -+ int speed; -+ u32 phy_mode, clk_select; -+ char modes[9][8] = { "OFF", "SDR", "DDR", "NA", "CDR_LO", -+ "NA", "NA", "NA", "CDR_HI" }; -+ -+ if (state != LTPI_LINK_MNG_ST_OP) { -+ sprintf(state_str, "LTPI: not linked\n"); -+ } else { -+ phy_mode = FIELD_GET(REG_LTPI_PHY_MODE, readl(priv->phy_regs + LTPI_PHY_CTRL)); -+ clk_select = FIELD_GET(REG_LTPI_PLL_SELECT, readl(priv->phy_regs + LTPI_PLL_CTRL)); -+ if (clk_select == REG_LTPI_PLL_LPLL) -+ speed = scu_get_pll_freq(priv, priv->index) / 1000000; -+ else -+ speed = 25; -+ -+ sprintf(state_str, -+ "LTPI%d:\n" -+ " link partner : %s\n" -+ " link mode : %s\n" -+ " link bandwidth : %dMbps\n", -+ priv->index, -+ ltpi_get_link_partner(priv) ? "ast1700" : "fpga", -+ &modes[phy_mode][0], speed); -+ } -+ -+ return sprintf(buf, "%s\n", state_str); -+} -+ -+/* Device attributes */ -+static DEVICE_ATTR_RW(ad_timeout); -+static DEVICE_ATTR_RW(io_driving); -+static DEVICE_ATTR_RW(clk_inverse); -+static DEVICE_ATTR_RW(link_speed_frm_rx_cnt); -+static DEVICE_ATTR_RW(disable_auto_downshift); -+static DEVICE_ATTR_RW(crc_format); -+static DEVICE_ATTR_RW(phy_speed_cap); -+static DEVICE_ATTR_RW(op_timeout); -+static DEVICE_ATTR_WO(rescan); -+static DEVICE_ATTR_RO(link_status); -+ -+static struct attribute *aspeed_ltpi_attrs[] = { -+ &dev_attr_ad_timeout.attr, -+ &dev_attr_io_driving.attr, -+ &dev_attr_clk_inverse.attr, -+ &dev_attr_link_speed_frm_rx_cnt.attr, -+ &dev_attr_disable_auto_downshift.attr, -+ &dev_attr_crc_format.attr, -+ &dev_attr_phy_speed_cap.attr, -+ &dev_attr_op_timeout.attr, -+ &dev_attr_rescan.attr, -+ &dev_attr_link_status.attr, -+ NULL, -+}; -+ -+static const struct attribute_group aspeed_ltpi_attr_group = { -+ .attrs = aspeed_ltpi_attrs, -+}; -+ - static int aspeed_ltpi_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -140,11 +981,13 @@ static int aspeed_ltpi_probe(struct platform_device *pdev) - const struct of_device_id *match; - struct aspeed_ltpi_priv *priv; - int irq, ret; -+ struct resource *res; - - match = of_match_device(dev->driver->of_match_table, dev); - - if (match) { -- if (of_property_match_string(np, "compatible", match->compatible) < 0) -+ if (of_property_match_string(np, "compatible", -+ match->compatible) < 0) - return -ENODEV; - } else { - return -ENODEV; -@@ -155,10 +998,30 @@ static int aspeed_ltpi_probe(struct platform_device *pdev) - return -ENOMEM; - - priv->dev = dev; -- priv->regs = devm_platform_ioremap_resource(pdev, 0); -+ priv->regs = devm_platform_ioremap_resource_byname(pdev, "base"); -+ if (IS_ERR(priv->regs)) -+ priv->regs = -+ devm_platform_ioremap_resource(pdev, 0); // Fallback - if (IS_ERR(priv->regs)) - return PTR_ERR(priv->regs); - -+ priv->phy_regs = devm_platform_ioremap_resource_byname(pdev, "phy"); -+ if (IS_ERR(priv->phy_regs)) -+ priv->phy_regs = -+ priv->regs + 0x200; // Fallback unsafe if size small -+ -+ priv->top_regs = devm_platform_ioremap_resource_byname(pdev, "top"); -+ if (IS_ERR(priv->top_regs)) -+ priv->top_regs = -+ priv->regs + 0x800; // Fallback unsafe if size small -+ -+ /* Identify index based on physical address for PLL control */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res && (res->start & 0x1000)) -+ priv->index = 1; -+ else -+ priv->index = 0; -+ - priv->version = (enum chip_version)device_get_match_data(dev); - - priv->ltpi_clk = devm_clk_get(&pdev->dev, "ltpi"); -@@ -178,7 +1041,8 @@ static int aspeed_ltpi_probe(struct platform_device *pdev) - priv->ltpi_phyclk = NULL; - } - -- priv->ltpi_rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); -+ priv->ltpi_rst = -+ devm_reset_control_get_optional_shared(&pdev->dev, NULL); - if (IS_ERR(priv->ltpi_rst)) - return PTR_ERR(priv->ltpi_rst); - -@@ -201,6 +1065,10 @@ static int aspeed_ltpi_probe(struct platform_device *pdev) - priv->uart_tunneling = ret; - - priv->scu = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); -+ if (IS_ERR(priv->scu)) { -+ dev_err(&pdev->dev, "failed to get SCU regmap\n"); -+ return PTR_ERR(priv->scu); -+ } - if (of_get_property(np, "remote-controller", NULL)) { - u32 reg; - -@@ -226,13 +1094,36 @@ static int aspeed_ltpi_probe(struct platform_device *pdev) - return ret; - } - -- writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_STATUS); -+ writel(LTPI_INTR_EN_OP_LINK_LOST, -+ priv->regs + LTPI_INTR_STATUS); - writel(LTPI_INTR_EN_OP_LINK_LOST, priv->regs + LTPI_INTR_EN); - } - -+ /* Initialize training parameters with defaults */ -+ priv->ad_timeout = ADVERTISE_TIMEOUT_US; -+ priv->io_driving = 0x2; -+ priv->clk_inverse = 0x0; -+ priv->link_speed_frm_rx_cnt = 4; -+ priv->disable_auto_downshift = 0; -+ priv->crc_format = 0; -+ priv->otp_ddr_dis = false; -+ priv->op_timeout = 2000000000; /* 2 seconds timeout by default */ -+ priv->phy_speed_cap = LTPI_SP_CAP_ASPEED_SUPPORTED; -+ - aspeed_ltpi_init_mux(priv); - - platform_set_drvdata(pdev, priv); -+ -+ /* Create sysfs attributes */ -+ ret = sysfs_create_group(&dev->kobj, &aspeed_ltpi_attr_group); -+ if (ret) { -+ dev_err(dev, "Failed to create sysfs group\n"); -+ reset_control_assert(priv->ltpi_rst); -+ clk_disable_unprepare(priv->ltpi_phyclk); -+ clk_disable_unprepare(priv->ltpi_clk); -+ return ret; -+ } -+ - if (np) - of_platform_populate(np, NULL, lookup, priv->dev); - -@@ -244,14 +1135,24 @@ static void aspeed_ltpi_remove(struct platform_device *pdev) - struct aspeed_ltpi_priv *priv; - - priv = platform_get_drvdata(pdev); -+ -+ /* Remove sysfs attributes */ -+ sysfs_remove_group(&pdev->dev.kobj, &aspeed_ltpi_attr_group); -+ - reset_control_assert(priv->ltpi_rst); - clk_disable_unprepare(priv->ltpi_phyclk); - clk_disable_unprepare(priv->ltpi_clk); - } - - static const struct of_device_id aspeed_ltpi_of_match[] = { -- { .compatible = "aspeed-ltpi", .data = (const void *)AST2700,}, -- { .compatible = "aspeed-ast1700-ltpi", .data = (const void *)AST1700,}, -+ { -+ .compatible = "aspeed-ltpi", -+ .data = (const void *)AST2700, -+ }, -+ { -+ .compatible = "aspeed-ast1700-ltpi", -+ .data = (const void *)AST1700, -+ }, - { /* sentinel */ } - }; - MODULE_DEVICE_TABLE(of, aspeed_ltpi_of_match); -diff --git a/drivers/bus/aspeed-ltpi.h b/drivers/bus/aspeed-ltpi.h -new file mode 100644 -index 000000000..6c9e49f62 ---- /dev/null -+++ b/drivers/bus/aspeed-ltpi.h -@@ -0,0 +1,276 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (c) 2024 ASPEED Technology Inc. -+ */ -+#ifndef __ASPEED_LTPI_H__ -+#define __ASPEED_LTPI_H__ -+ -+#include -+ -+/* OCP_DC-SCM_2.0_LTPI_ver_1.0, Table 21 LTPI speed capability encoding */ -+#define LTPI_SP_CAP_25M BIT(0) -+#define LTPI_SP_CAP_50M BIT(1) -+#define LTPI_SP_CAP_75M BIT(2) -+#define LTPI_SP_CAP_100M BIT(3) -+#define LTPI_SP_CAP_150M BIT(4) -+#define LTPI_SP_CAP_200M BIT(5) -+#define LTPI_SP_CAP_250M BIT(6) -+#define LTPI_SP_CAP_300M BIT(7) -+#define LTPI_SP_CAP_400M BIT(8) -+#define LTPI_SP_CAP_600M BIT(9) -+#define LTPI_SP_CAP_800M BIT(10) -+#define LTPI_SP_CAP_1G BIT(11) -+#define LTPI_SP_CAP_500M BIT(12) /* Aspeed only */ -+/* --gap-- */ -+#define LTPI_SP_CAP_DDR BIT(15) -+ -+#define LTPI_SP_CAP_ASPEED_SUPPORTED \ -+ (LTPI_SP_CAP_25M | LTPI_SP_CAP_50M | LTPI_SP_CAP_75M | \ -+ LTPI_SP_CAP_100M | LTPI_SP_CAP_150M | LTPI_SP_CAP_200M | \ -+ LTPI_SP_CAP_250M | LTPI_SP_CAP_300M | LTPI_SP_CAP_400M | \ -+ LTPI_SP_CAP_500M | LTPI_SP_CAP_DDR) -+ -+/* control registers */ -+#define LTPI_LINK_ST 0x000 -+#define REG_LTPI_LINK_ST_LOCAL GENMASK(19, 16) -+#define REG_LTPI_LINK_ST_REMOTE GENMASK(15, 12) -+#define REG_LTPI_LINK_SPEED GENMASK(11, 8) -+#define REG_LTPI_LINK_DDR_MODE BIT(7) -+#define REG_LTPI_LINK_ST_RESERVED BIT(6) -+#define REG_LTPI_CON_ACC_TO_ERR BIT(5) -+#define REG_LTPI_LINK_SP_TO_ERR BIT(4) -+#define REG_LTPI_UNKNOWN_COMMA_ERR BIT(3) -+#define REG_LTPI_FRM_CRC_ERR BIT(2) -+#define REG_LTPI_LINK_LOST_ERR BIT(1) -+#define REG_LTPI_LINK_ALIGN BIT(0) -+ -+#define LTPI_CAP_LOCAL 0x004 -+#define REG_LTPI_SP_CAP_LOCAL GENMASK(23, 8) -+#define REG_LTPI_MAJOR_VER_LOCAL GENMASK(7, 4) -+#define REG_LTPI_MIN_VER_LOCAL GENMASK(3, 0) -+#define LTPI_CAP_REMOTE 0x008 -+#define REG_LTPI_SP_CAP_REMOTE GENMASK(23, 8) -+#define REG_LTPI_MAJOR_VER_REMOTE GENMASK(7, 4) -+#define REG_LTPI_MIN_VER_REMOTE GENMASK(3, 0) -+#define LTPI_PF_ID_LOCAL 0x00C -+#define LTPI_PF_ID_REMOTE 0x010 -+#define LTPI_AD_CAP_LOW_LOCAL 0x014 -+#define LTPI_AD_CAP_HIGH_LOCAL 0x018 -+#define LTPI_AD_CAP_LOW_REMOTE 0x01C -+#define LTPI_AD_CAP_HIGH_REMOTE 0x020 -+#define LTPI_DEFAULT_CON_LOW 0x024 -+#define LTPI_DEFAULT_CON_HIGH 0x028 -+#define LTPI_LINK_ALIGN_ERR_CNT 0x02C -+#define LTPI_LINK_LOST_ERR_CNT 0x030 -+#define LTPI_CRC_ERR_CNT 0x034 -+#define LTPI_UNKNOWN_COMMA_ERR_CNT 0x038 -+#define LTPI_LINK_SP_TO_ERR_CNT 0x03C -+#define LTPI_CON_ACC_TO_ERR_CNT 0x040 -+#define LTPI_LINK_TRAIN_RX_FRM_CNT_LOW 0x044 -+#define REG_LTPI_CON_ACC_FRM_RX_CNT GENMASK(31, 24) -+#define REG_LTPI_LINK_SP_FRM_RX_CNT GENMASK(23, 16) -+#define REG_LTPI_LINK_DET_FRM_RX_CNT GENMASK(15, 0) -+#define LTPI_LINK_TRAIN_RX_FRM_CNT_HIGH 0x048 -+#define LTPI_LINK_TRAIN_TX_FRM_CNT_LOW 0x04C -+#define REG_LTPI_CON_ACC_FRM_TX_CNT GENMASK(31, 24) -+#define REG_LTPI_LINK_SP_FRM_TX_CNT GENMASK(23, 16) -+#define REG_LTPI_LINK_DET_FRM_TX_CNT GENMASK(15, 0) -+#define LTPI_LINK_TRAIN_TX_FRM_CNT_HIGH 0x050 -+#define LTPI_OP_RX_FRM_CNT 0x054 -+#define LTPI_OP_TX_FRM_CNT 0x058 -+#define LTPI_LINK_LOST_CNT 0x05c -+#define REG_LTPI_AD_ALIGN_TO_CNT GENMASK(27, 24) -+#define REG_LTPI_LINK_LOST_OP_CNT GENMASK(23, 16) -+#define REG_LTPI_LINK_LOST_CON_OR_ACC_CNT GENMASK(15, 8) -+#define REG_LTPI_LINK_LOST_AD_CNT GENMASK(7, 0) -+#define LTPI_LINK_CONTROL 0x080 -+#define REG_LTPI_TRIG_CON_ST BIT(11) -+#define REG_LTPI_AUTO_CON_ST BIT(10) -+#define REG_LTPI_DATA_CH_RST BIT(9) -+#define REG_LTPI_I2C_RST GENMASK(8, 2) -+#define REG_LTPI_LINK_RETRAIN_REQ BIT(1) -+#define REG_LTPI_LINK_SW_RST BIT(0) -+ -+#define LTPI_INTR 0x100 -+#define REG_LTPI_LINK_HALT BIT(24) -+#define REG_LTPI_DATA_CH_DROP_FRAME BIT(23) -+#define REG_LTPI_DATA_CH_INVALID_ACCESS BIT(22) -+#define REG_LTPI_I2C5_TO_ERR BIT(21) -+#define REG_LTPI_I2C4_TO_ERR BIT(20) -+#define REG_LTPI_I2C3_TO_ERR BIT(19) -+#define REG_LTPI_I2C2_TO_ERR BIT(18) -+#define REG_LTPI_I2C1_TO_ERR BIT(17) -+#define REG_LTPI_I2C0_TO_ERR BIT(16) -+#define REG_LTPI_AD_ALIGN_TO BIT(12) -+#define REG_LTPI_HW_RETRY_LINK_DET_STUCK_TO_ERR BIT(11) -+#define REG_LTPI_HW_RETRY_TO_ERR BIT(10) -+#define REG_LTPI_OP_LINK_LOST_ERR BIT(4) -+#define REG_LTPI_CON_OR_ACC_LINK_LOST_ERR BIT(3) -+#define REG_LTPI_AD_LINK_LOST_ERR BIT(2) -+#define REG_LTPI_CON_READY BIT(1) -+#define REG_LTPI_AD_READY BIT(0) -+#define LTPI_INTR_EN 0x104 -+#define REG_LTPI_LINK_HALT_INTR_EN BIT(24) -+#define REG_LTPI_DATA_CH_DROP_FRAME_EN BIT(23) -+#define REG_LTPI_DATA_CH_INVALID_ACCESS_EN BIT(22) -+#define REG_LTPI_I2C5_TO_ERR_EN BIT(21) -+#define REG_LTPI_I2C4_TO_ERR_EN BIT(20) -+#define REG_LTPI_I2C3_TO_ERR_EN BIT(19) -+#define REG_LTPI_I2C2_TO_ERR_EN BIT(18) -+#define REG_LTPI_I2C1_TO_ERR_EN BIT(17) -+#define REG_LTPI_I2C0_TO_ERR_EN BIT(16) -+#define REG_LTPI_AD_ALIGN_TO_EN BIT(12) -+#define REG_LTPI_HW_RETRY_LINK_DET_STUCK_TO_ERR_EN BIT(11) -+#define REG_LTPI_HW_RETRY_TO_ERR_EN BIT(10) -+#define REG_LTPI_CON_ACC_TO_ERR_EN BIT(9) -+#define REG_LTPI_LINK_SP_TO_ERR_EN BIT(8) -+#define REG_LTPI_UNKNOWN_COMMA_ERR_EN BIT(7) -+#define REG_LTPI_FRM_CRC_ERR_EN BIT(6) -+#define REG_LTPI_LINK_LOST_ERR_EN BIT(5) -+#define REG_LTPI_OP_LINK_LOST_ERR_EN BIT(4) -+#define REG_LTPI_CON_OR_ACC_LINK_LOST_ERR_EN BIT(3) -+#define REG_LTPI_AD_LINK_LOST_ERR_EN BIT(2) -+#define REG_LTPI_CON_READY_EN BIT(1) -+#define REG_LTPI_AD_READY_EN BIT(0) -+#define LTPI_LINK_MNG_ST 0x108 -+#define REG_LTPI_LINK_PARTNER_FLAG BIT(24) -+#define REG_LTPI_LINK_PARTNER_FPGA 0b0 -+#define REG_LTPI_LINK_PARTNER_1700 0b1 -+#define REG_LTPI_SP_INTERSETION GENMASK(23, 8) -+#define REG_LTPI_LINK_MNG_ST GENMASK(3, 0) -+#define LTPI_LINK_MNG_ST_DETECT_ALIGN 0 -+#define LTPI_LINK_MNG_ST_DETECT 1 -+#define LTPI_LINK_MNG_ST_SPEED 2 -+#define LTPI_LINK_MNG_ST_WAIT_PLL_SET 3 -+#define LTPI_LINK_MNG_ST_ADV_ALIGN 4 -+#define LTPI_LINK_MNG_ST_ADV 5 -+#define LTPI_LINK_MNG_ST_CONFIG_ACC 6 -+#define LTPI_LINK_MNG_ST_OP 7 -+#define LTPI_LINK_MANAGE_CTRL0 0x10C -+#define REG_LTPI_LINK_PARTNER_CHKNUM GENMASK(19, 16) -+#define REG_LTPI_CON_FRM_NOCHK BIT(8) -+#define REG_LTPI_TX_LINK_SP_FRM_NUM GENMASK(7, 4) -+#define REG_LTPI_RX_LINK_SP_FRM_NUM GENMASK(3, 0) -+#define LTPI_LINK_MANAGE_CTRL1 0x110 -+#define LTPI_LINK_MANAGE_CTRL2 0x114 -+#define LTPI_CON_CAP_LOW 0x118 -+#define LTPI_CON_CAP_HIGH 0x11C -+#define LTPI_MAC_CTRL 0x120 -+#define LTPI_AHB_CTRL0 0x124 -+#define REG_LTPI_AHB_ADDR_MAP1 GENMASK(25, 16) -+#define REG_LTPI_AHB_ADDR_MAP0 GENMASK(9, 0) -+#define LTPI_AHB_CTRL1 0x128 -+#define REG_LTPI_AHB_ADDR_MAP3 GENMASK(25, 16) -+#define REG_LTPI_AHB_ADDR_MAP2 GENMASK(9, 0) -+#define LTPI_CRC_OPTION 0x12c -+#define REG_LTPI_SW_CRC_OUT_ML_FIRST BIT(2) -+#define REG_LTPI_SW_CRC_IN_LSB_FIRST BIT(1) -+#define REG_LTPI_CRC_SW_FORCE BIT(0) -+#define LTPI_I2C 0x130 -+#define REG_LTPI_I2C_SLV_MST_SWITCH_SW_EN BIT(8) -+#define REG_LTPI_I2C_SLV_EN GENMASK(5, 0) -+ -+#define LTPI_OEM_BUS_SETTING 0x188 -+#define REG_LTPI_OEM_RX_START_TRIG BIT(1) -+#define REG_LTPI_OEM_TX_START_TRIG BIT(0) -+ -+#define LTPI_OEM_DBG0 0x190 -+#define REG_LTPI_OEM_RX_INIT_DONE BIT(9) -+#define REG_LTPI_OEM_TX_INIT_DONE BIT(8) -+ -+#define LTPI_DATA_CH_CFG0 0x1D8 -+#define REG_LTPI_DATA_CH_TAG_CHK_EN BIT(2) -+#define REG_LTPI_DATA_CH_ADDR_CHK_EN BIT(1) -+#define REG_LTPI_DATA_CH_WAIT_ACK_TO_EN BIT(0) -+ -+/* LTPI PHY control registers */ -+#define LTPI_PHY_CTRL 0x000 -+#define REG_LTPI_PHY_MODE GENMASK(3, 0) -+#define LTPI_PHY_MODE_CDR_HI_SP 0b1000 -+#define LTPI_PHY_MODE_CDR_LO_SP 0b0100 -+#define LTPI_PHY_MODE_DDR 0b0010 -+#define LTPI_PHY_MODE_SDR 0b0001 -+#define LTPI_PHY_MODE_OFF 0b0000 -+#define LTPI_PLL_CTRL 0x004 -+#define REG_LTPI_RX_PHY_CLK_INV BIT(9) -+#define REG_LTPI_TX_PHY_CLK_INV BIT(8) -+#define REG_LTPI_PLL_SET BIT(4) -+#define REG_LTPI_RX_PLL_DIV2 BIT(3) -+#define REG_LTPI_PLL_SELECT GENMASK(2, 0) -+#define REG_LTPI_PLL_25M 0 -+/* AST2700A0 */ -+#define REG_LTPI_PLL_50M 1 -+#define REG_LTPI_PLL_100M 2 -+#define REG_LTPI_PLL_200M 3 -+#define REG_LTPI_PLL_250M 4 -+#define REG_LTPI_PLL_400M 5 -+#define REG_LTPI_PLL_800M 6 -+#define REG_LTPI_PLL_1G 7 -+/* AST2700A1 */ -+#define REG_LTPI_PLL_LPLL 7 -+ -+#define LTPI_PHY_ALIGN_CTRL 0x008 -+#define LTPI_DLL_CTRL 0x00C -+#define REG_LTPI_SW_DLL_RST BIT(26) -+#define REG_LTPI_FORCE_DLL_RST BIT(25) -+#define REG_LTPI_DLL_PD BIT(24) -+#define REG_LTPI_DLL_TSTCTRL GENMASK(23, 16) -+#define REG_LTPI_DLL_RST_TIMEOUT_A0 GENMASK(15, 0) -+#define REG_LTPI_DLL_CLK_2X BIT(8) -+#define REG_LTPI_DLL_RST_TIMEOUT GENMASK(7, 0) -+#define LTPI_PHY_HI_SP_CDR_CTRL 0x010 -+#define REG_LTPI_SW_HI_SP_CDR_EN BIT(10) -+#define REG_LTPI_FORCE_HI_SP_CDR_EN BIT(9) -+#define REG_LTPI_HI_SP_CDR_EN_TIMEOUT_EN BIT(8) -+#define LTPI_HI_SP_CDR_EN_TIMEOUT GENMASK(7, 0) -+ -+#define LTPI_PROT_KEY 0x34 -+#define LTPI_PROT_KEY_UNLOCK 0x1728aacc -+ -+/* LVDS TOP registers */ -+#define LTPI_LVDS_TX_CTRL 0x000 -+#define REG_LTPI_LVDS_TX1_DS1 BIT(22) -+#define REG_LTPI_LVDS_TX1_DS0 BIT(21) -+#define REG_LTPI_LVDS_TX1_IPREE BIT(20) -+#define REG_LTPI_LVDS_TX1_IPREE_EN BIT(19) -+#define REG_LTPI_LVDS_TX1_PD BIT(18) -+#define REG_LTPI_LVDS_TX1_PU BIT(17) -+#define REG_LTPI_LVDS_TX1_OE BIT(16) -+#define REG_LTPI_LVDS_TX0_DS1 BIT(6) -+#define REG_LTPI_LVDS_TX0_DS0 BIT(5) -+#define REG_LTPI_LVDS_TX0_IPREE BIT(4) -+#define REG_LTPI_LVDS_TX0_IPREE_EN BIT(3) -+#define REG_LTPI_LVDS_TX0_PD BIT(2) -+#define REG_LTPI_LVDS_TX0_PU BIT(1) -+#define REG_LTPI_LVDS_TX0_OE BIT(0) -+#define LTPI_LVDS_RX_CTRL 0x004 -+#define REG_LTPI_LVDS_RX1_BIAS_EN BIT(18) -+#define REG_LTPI_LVDS_RX1_ST BIT(17) -+#define REG_LTPI_LVDS_RX1_IE BIT(16) -+#define REG_LTPI_LVDS_RX0_BIAS_EN BIT(2) -+#define REG_LTPI_LVDS_RX0_ST BIT(1) -+#define REG_LTPI_LVDS_RX0_IE BIT(0) -+#define LTPI_SW_RST 0x008 -+#define REG_LTPI_ALL_SW_RST BIT(31) -+#define REG_LTPI1_SW_RST BIT(17) -+#define REG_LTPI0_SW_RST BIT(16) -+#define REG_LTPI_DLL_CTRL_SW_RST BIT(9) -+#define REG_LTPI_REF_SW_RST BIT(8) -+#define REG_LTPI1_RX_PHY_SW_RST BIT(7) -+#define REG_LTPI1_TX_PHY_SW_RST BIT(6) -+#define REG_LTPI1_RX_MAC_SW_RST BIT(5) -+#define REG_LTPI1_TX_MAC_SW_RST BIT(4) -+#define REG_LTPI0_RX_PHY_SW_RST BIT(3) -+#define REG_LTPI0_TX_PHY_SW_RST BIT(2) -+#define REG_LTPI0_RX_MAC_SW_RST BIT(1) -+#define REG_LTPI0_TX_MAC_SW_RST BIT(0) -+#define LTPI_STRAP_VAL 0x00c -+#define REG_LTPI_STRAP_2LTPI_EN BIT(1) -+#define REG_LTPI_STRAP_1700_EN BIT(0) -+#define LTPI_SW_FORCE_EN 0x010 -+#define LTPI_SW_FORCE_VAL 0x014 -+#define REG_LTPI_SW_FORCE_LVDS_TX_DS_EN BIT(2) -+#define REG_LTPI_SW_FORCE_2LTPI_EN BIT(1) -+#define REG_LTPI_SW_FORCE_1700_EN BIT(0) -+ -+#endif /* __ASPEED_LTPI_H__ */ -diff --git a/drivers/clk/clk-ast1700.c b/drivers/clk/clk-ast1700.c -index 60c290352..1f24738b4 100644 ---- a/drivers/clk/clk-ast1700.c -+++ b/drivers/clk/clk-ast1700.c -@@ -25,6 +25,8 @@ - #define AST1700_UXCLK_CTRL 0x330 - #define AST1700_HUXCLK_CTRL 0x334 - -+#define CREATE_CLK_NAME(id, suffix) kasprintf(GFP_KERNEL, "ast1700_%d-%s", id, suffix) -+ - static DEFINE_IDA(ast1700_clk_ida); - - /* Globally visible clocks */ -@@ -82,7 +84,7 @@ static const struct clk_div_table ast1700_clk_div_table2[] = { - { 0 } - }; - --static struct clk_hw *AST1700_calc_uclk(const char *name, u32 val) -+static struct clk_hw *AST1700_calc_uclk(int id, u32 val) - { - unsigned int mult, div; - -@@ -93,10 +95,11 @@ static struct clk_hw *AST1700_calc_uclk(const char *name, u32 val) - mult = r; - div = n * 2; - -- return clk_hw_register_fixed_factor(NULL, name, "ast1700-uxclk", 0, mult, div); -+ return clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "uartxclk"), -+ CREATE_CLK_NAME(id, "uxclk"), 0, mult, div); - }; - --static struct clk_hw *AST1700_calc_huclk(const char *name, u32 val) -+static struct clk_hw *AST1700_calc_huclk(int id, u32 val) - { - unsigned int mult, div; - -@@ -107,7 +110,8 @@ static struct clk_hw *AST1700_calc_huclk(const char *name, u32 val) - mult = r; - div = n * 2; - -- return clk_hw_register_fixed_factor(NULL, name, "ast1700-huxclk", 0, mult, div); -+ return clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "huartxclk"), -+ CREATE_CLK_NAME(id, "huxclk"), 0, mult, div); - }; - - static struct clk_hw *AST1700_calc_pll(const char *name, const char *parent_name, u32 val) -@@ -280,8 +284,6 @@ static const char *const uxclk_sel1[] = { - "ast1700_1-hpll", - }; - --#define CREATE_CLK_NAME(id, suffix) kasprintf(GFP_KERNEL, "ast1700_%d-%s", id, suffix) -- - static int AST1700_clk_init(struct device_node *ast1700_node) - { - struct clk_hw_onecell_data *clk_data; -@@ -362,7 +364,7 @@ static int AST1700_clk_init(struct device_node *ast1700_node) - 0, 2, 0, &ast1700_clk_lock); - - val = readl(clk_base + AST1700_UXCLK_CTRL); -- clks[AST1700_CLK_UARTX] = AST1700_calc_uclk(CREATE_CLK_NAME(id, "uartxclk"), val); -+ clks[AST1700_CLK_UARTX] = AST1700_calc_uclk(id, val); - - /* huxclk mux selection */ - clks[AST1700_CLK_HUXCLK] = -@@ -373,7 +375,7 @@ static int AST1700_clk_init(struct device_node *ast1700_node) - 3, 2, 0, &ast1700_clk_lock); - - val = readl(clk_base + AST1700_HUXCLK_CTRL); -- clks[AST1700_CLK_HUARTX] = AST1700_calc_huclk(CREATE_CLK_NAME(id, "huartxclk"), val); -+ clks[AST1700_CLK_HUARTX] = AST1700_calc_huclk(id, val); - - /* AHB CLK = 200Mhz */ - clks[AST1700_CLK_AHB] = -diff --git a/drivers/clk/clk-ast2700.c b/drivers/clk/clk-ast2700.c -index c686e19d1..686881308 100644 ---- a/drivers/clk/clk-ast2700.c -+++ b/drivers/clk/clk-ast2700.c -@@ -47,39 +47,6 @@ - #define SCU1_UXCLK_CTRL 0x330 - #define SCU1_HUXCLK_CTRL 0x334 - #define SCU1_MAC12_CLK_DLY 0x390 --#define SCU1_MAC12_CLK_DLY_100M 0x394 --#define SCU1_MAC12_CLK_DLY_10M 0x398 -- --/* -- * MAC Clock Delay settings -- */ --#define MAC_CLK_RMII1_50M_RCLK_O_CTRL BIT(30) --#define MAC_CLK_RMII1_50M_RCLK_O_DIS 0 --#define MAC_CLK_RMII1_50M_RCLK_O_EN 1 --#define MAC_CLK_RMII0_50M_RCLK_O_CTRL BIT(29) --#define MAC_CLK_RMII0_5M_RCLK_O_DIS 0 --#define MAC_CLK_RMII0_5M_RCLK_O_EN 1 --#define MAC_CLK_RMII_TXD_FALLING_2 BIT(27) --#define MAC_CLK_RMII_TXD_FALLING_1 BIT(26) --#define MAC_CLK_RXCLK_INV_2 BIT(25) --#define MAC_CLK_RXCLK_INV_1 BIT(24) --#define MAC_CLK_1G_INPUT_DELAY_2 GENMASK(23, 18) --#define MAC_CLK_1G_INPUT_DELAY_1 GENMASK(17, 12) --#define MAC_CLK_1G_OUTPUT_DELAY_2 GENMASK(11, 6) --#define MAC_CLK_1G_OUTPUT_DELAY_1 GENMASK(5, 0) -- --#define MAC_CLK_100M_10M_RESERVED GENMASK(31, 26) --#define MAC_CLK_100M_10M_RXCLK_INV_2 BIT(25) --#define MAC_CLK_100M_10M_RXCLK_INV_1 BIT(24) --#define MAC_CLK_100M_10M_INPUT_DELAY_2 GENMASK(23, 18) --#define MAC_CLK_100M_10M_INPUT_DELAY_1 GENMASK(17, 12) --#define MAC_CLK_100M_10M_OUTPUT_DELAY_2 GENMASK(11, 6) --#define MAC_CLK_100M_10M_OUTPUT_DELAY_1 GENMASK(5, 0) -- --#define AST2700_DEF_MAC12_DELAY_1G_A0 0x00CF4D75 --#define AST2700_DEF_MAC12_DELAY_1G_A1 0x005D6618 --#define AST2700_DEF_MAC12_DELAY_100M 0x00410410 --#define AST2700_DEF_MAC12_DELAY_10M 0x00410410 - - struct mac_delay_config { - u32 tx_delay_1000; -@@ -1054,62 +1021,6 @@ static struct clk_hw *ast2700_clk_hw_register_gate(struct device *dev, const cha - return hw; - } - --static void ast2700_soc1_configure_mac01_clk(struct ast2700_clk_ctrl *clk_ctrl) --{ -- struct device_node *np = clk_ctrl->dev->of_node; -- struct mac_delay_config mac_cfg; -- u32 reg[3]; -- int ret; -- -- if (readl(clk_ctrl->base) & REVISION_ID) { -- if ((readl(clk_ctrl->base + SCU1_MAC12_CLK_DLY) & GENMASK(25, 0)) == 0) -- reg[0] = AST2700_DEF_MAC12_DELAY_1G_A1; -- else -- reg[0] = readl(clk_ctrl->base + SCU1_MAC12_CLK_DLY); -- } else { -- reg[0] = AST2700_DEF_MAC12_DELAY_1G_A0; -- } -- reg[1] = AST2700_DEF_MAC12_DELAY_100M; -- reg[2] = AST2700_DEF_MAC12_DELAY_10M; -- -- ret = of_property_read_u32_array(np, "mac0-clk-delay", (u32 *)&mac_cfg, -- sizeof(mac_cfg) / sizeof(u32)); -- if (!ret) { -- reg[0] &= ~(MAC_CLK_1G_INPUT_DELAY_1 | MAC_CLK_1G_OUTPUT_DELAY_1); -- reg[0] |= FIELD_PREP(MAC_CLK_1G_INPUT_DELAY_1, mac_cfg.rx_delay_1000) | -- FIELD_PREP(MAC_CLK_1G_OUTPUT_DELAY_1, mac_cfg.tx_delay_1000); -- -- reg[1] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_1 | MAC_CLK_100M_10M_OUTPUT_DELAY_1); -- reg[1] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_1, mac_cfg.rx_delay_100) | -- FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_1, mac_cfg.tx_delay_100); -- -- reg[2] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_1 | MAC_CLK_100M_10M_OUTPUT_DELAY_1); -- reg[2] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_1, mac_cfg.rx_delay_10) | -- FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_1, mac_cfg.tx_delay_10); -- } -- -- ret = of_property_read_u32_array(np, "mac1-clk-delay", (u32 *)&mac_cfg, -- sizeof(mac_cfg) / sizeof(u32)); -- if (!ret) { -- reg[0] &= ~(MAC_CLK_1G_INPUT_DELAY_2 | MAC_CLK_1G_OUTPUT_DELAY_2); -- reg[0] |= FIELD_PREP(MAC_CLK_1G_INPUT_DELAY_2, mac_cfg.rx_delay_1000) | -- FIELD_PREP(MAC_CLK_1G_OUTPUT_DELAY_2, mac_cfg.tx_delay_1000); -- -- reg[1] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_2 | MAC_CLK_100M_10M_OUTPUT_DELAY_2); -- reg[1] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_2, mac_cfg.rx_delay_100) | -- FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_2, mac_cfg.tx_delay_100); -- -- reg[2] &= ~(MAC_CLK_100M_10M_INPUT_DELAY_2 | MAC_CLK_100M_10M_OUTPUT_DELAY_2); -- reg[2] |= FIELD_PREP(MAC_CLK_100M_10M_INPUT_DELAY_2, mac_cfg.rx_delay_10) | -- FIELD_PREP(MAC_CLK_100M_10M_OUTPUT_DELAY_2, mac_cfg.tx_delay_10); -- } -- -- reg[0] |= (readl(clk_ctrl->base + SCU1_MAC12_CLK_DLY) & ~GENMASK(25, 0)); -- writel(reg[0], clk_ctrl->base + SCU1_MAC12_CLK_DLY); -- writel(reg[1], clk_ctrl->base + SCU1_MAC12_CLK_DLY_100M); -- writel(reg[2], clk_ctrl->base + SCU1_MAC12_CLK_DLY_10M); --} -- - static void ast2700_soc1_configure_i3c_clk(struct ast2700_clk_ctrl *clk_ctrl) - { - if (readl(clk_ctrl->base) & REVISION_ID) { -@@ -1181,7 +1092,6 @@ static int ast2700_soc_clk_probe(struct platform_device *pdev) - writel(val | uart_clk_source, clk_base + SCU1_CLK_SEL1); - } - -- ast2700_soc1_configure_mac01_clk(clk_ctrl); - ast2700_soc1_configure_i3c_clk(clk_ctrl); - } - -diff --git a/drivers/crypto/aspeed/aspeed-rsss-rsa.c b/drivers/crypto/aspeed/aspeed-rsss-rsa.c -index 1a777e97d..c019d8303 100644 ---- a/drivers/crypto/aspeed/aspeed-rsss-rsa.c -+++ b/drivers/crypto/aspeed/aspeed-rsss-rsa.c -@@ -249,7 +249,7 @@ static int aspeed_rsa_trigger(struct aspeed_rsss_dev *rsss_dev) - cipher = crypto_akcipher_reqtfm(req); - ctx = akcipher_tfm_ctx(cipher); - -- if (!ctx->n || !ctx->n_sz) { -+ if (!ctx->n_sz) { - dev_err(rsss_dev->dev, "%s: key n is not set\n", __func__); - return -EINVAL; - } -@@ -273,7 +273,7 @@ static int aspeed_rsa_trigger(struct aspeed_rsss_dev *rsss_dev) - req->dst_len = nm / 8; - - if (ctx->enc) { -- if (!ctx->e || !ctx->e_sz) { -+ if (!ctx->e_sz) { - dev_err(rsss_dev->dev, "%s: key e is not set\n", - __func__); - return -EINVAL; -@@ -283,7 +283,7 @@ static int aspeed_rsa_trigger(struct aspeed_rsss_dev *rsss_dev) - ctx->e, ctx->e_sz, - ASPEED_RSA_EXP_MODE); - } else { -- if (!ctx->d || !ctx->d_sz) { -+ if (!ctx->d_sz) { - dev_err(rsss_dev->dev, "%s: key d is not set\n", - __func__); - return -EINVAL; -@@ -341,18 +341,11 @@ static int aspeed_rsa_dec(struct akcipher_request *req) - return aspeed_rsa_handle_queue(rsss_dev, req); - } - --static u8 *aspeed_rsa_key_copy(u8 *src, size_t len) --{ -- return kmemdup(src, len, GFP_KERNEL); --} -- - static int aspeed_rsa_set_n(struct aspeed_rsa_ctx *ctx, u8 *value, - size_t len) - { - ctx->n_sz = len; -- ctx->n = aspeed_rsa_key_copy(value, len); -- if (!ctx->n) -- return -ENOMEM; -+ memcpy(ctx->n, value, len); - - return 0; - } -@@ -361,9 +354,7 @@ static int aspeed_rsa_set_e(struct aspeed_rsa_ctx *ctx, u8 *value, - size_t len) - { - ctx->e_sz = len; -- ctx->e = aspeed_rsa_key_copy(value, len); -- if (!ctx->e) -- return -ENOMEM; -+ memcpy(ctx->e, value, len); - - return 0; - } -@@ -372,23 +363,11 @@ static int aspeed_rsa_set_d(struct aspeed_rsa_ctx *ctx, u8 *value, - size_t len) - { - ctx->d_sz = len; -- ctx->d = aspeed_rsa_key_copy(value, len); -- if (!ctx->d) -- return -ENOMEM; -+ memcpy(ctx->d, value, len); - - return 0; - } - --static void aspeed_rsa_key_free(struct aspeed_rsa_ctx *ctx) --{ -- kfree_sensitive(ctx->n); -- kfree_sensitive(ctx->e); -- kfree_sensitive(ctx->d); -- ctx->n_sz = 0; -- ctx->e_sz = 0; -- ctx->d_sz = 0; --} -- - static int aspeed_rsa_setkey(struct crypto_akcipher *tfm, const void *key, - unsigned int keylen, int priv) - { -@@ -416,29 +395,17 @@ static int aspeed_rsa_setkey(struct crypto_akcipher *tfm, const void *key, - return 0; - - hexdump("n", (u8 *)ctx->key.n, ctx->key.n_sz); -- ret = aspeed_rsa_set_n(ctx, (u8 *)ctx->key.n, ctx->key.n_sz); -- if (ret) -- goto err; -+ aspeed_rsa_set_n(ctx, (u8 *)ctx->key.n, ctx->key.n_sz); - - hexdump("e", (u8 *)ctx->key.e, ctx->key.e_sz); -- ret = aspeed_rsa_set_e(ctx, (u8 *)ctx->key.e, ctx->key.e_sz); -- if (ret) -- goto err; -+ aspeed_rsa_set_e(ctx, (u8 *)ctx->key.e, ctx->key.e_sz); - - if (priv) { - hexdump("d", (u8 *)ctx->key.d, ctx->key.d_sz); -- ret = aspeed_rsa_set_d(ctx, (u8 *)ctx->key.d, ctx->key.d_sz); -- if (ret) -- goto err; -+ aspeed_rsa_set_d(ctx, (u8 *)ctx->key.d, ctx->key.d_sz); - } - - return 0; -- --err: -- dev_err(rsss_dev->dev, "rsss set key failed\n"); -- aspeed_rsa_key_free(ctx); -- -- return ret; - } - - static int aspeed_rsa_set_pub_key(struct crypto_akcipher *tfm, -diff --git a/drivers/crypto/aspeed/aspeed-rsss.h b/drivers/crypto/aspeed/aspeed-rsss.h -index 1998c067b..8d9adc32f 100644 ---- a/drivers/crypto/aspeed/aspeed-rsss.h -+++ b/drivers/crypto/aspeed/aspeed-rsss.h -@@ -207,9 +207,9 @@ struct aspeed_rsa_ctx { - - struct rsa_key key; - int enc; -- u8 *n; -- u8 *e; -- u8 *d; -+ u8 n[ASPEED_RSA_MAX_KEY_LEN]; -+ u8 e[ASPEED_RSA_MAX_KEY_LEN]; -+ u8 d[ASPEED_RSA_MAX_KEY_LEN]; - size_t n_sz; - size_t e_sz; - size_t d_sz; -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h -index e2fabfcfa..1e9ef613a 100644 ---- a/drivers/gpu/drm/aspeed/aspeed_gfx.h -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h -@@ -11,6 +11,7 @@ struct aspeed_gfx { - struct reset_control *rst_crt; - struct reset_control *rst_engine; - struct regmap *scu; -+ struct regmap *scu1; - struct regmap *dp; - struct regmap *dpmcu; - struct regmap *pcie_ep; -@@ -100,6 +101,10 @@ int aspeed_gfx_create_output(struct drm_device *drm); - #define CRT_CTRL_VBLANK_LINE(x) (((x) << 20) & CRT_CTRL_VBLANK_LINE_MASK) - #define CRT_CTRL_VBLANK_LINE_MASK GENMASK(31, 20) - -+/* CURSOR define */ -+#define CRT_CTRL_CURSOR0 0x3f3f -+#define CRT_CTRL_CURSOR1 0xfff1fff -+ - /* CRT_HORIZ0 */ - #define CRT_H_TOTAL(x) (x) - #define CRT_H_DE(x) ((x) << 16) -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c -index c2f8f7d1e..75314bd3d 100644 ---- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c -@@ -52,9 +52,13 @@ static void aspeed_gfx_set_g6_clock_source(struct aspeed_gfx *priv, int mode_wid - - static void aspeed_gfx_set_g7_clock(struct aspeed_gfx *priv) - { -- /* apply 800 x 600 @ 62 on ast2700 */ -+ /* apply 800 x 600 @ 60 on ast2700 */ - regmap_update_bits(priv->scu, 0x288, BIT(14), BIT(14)); -- regmap_write(priv->scu, 0x340, 0x00130002); -+ regmap_write(priv->scu, 0x340, 0x00190002); -+ -+ /* apply 800 x 600 @ 60 on ast2700 DAC */ -+ regmap_update_bits(priv->scu1, 0xd0, BIT(10), BIT(10)); -+ regmap_write(priv->scu1, 0x320, 0x1048000F); - } - - static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) -@@ -100,8 +104,15 @@ static void aspeed_gfx_enable_controller(struct aspeed_gfx *priv) - regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_dp_bit, priv->soc_dp_bit); - } - -+ /* remove the cursor and osd usage */ -+ ctrl1 &= ~(CRT_CTRL_HW_CURSOR_EN | CRT_CTRL_OSD_EN); -+ - writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1); - writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); -+ -+ /* trigger cursor position to apply cursor disable */ -+ writel(CRT_CTRL_CURSOR0, priv->base + CRT_CURSOR0); -+ writel(CRT_CTRL_CURSOR1, priv->base + CRT_CURSOR1); - } - - static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv) -diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c -index b84eb84c0..a68575244 100644 ---- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c -@@ -206,6 +206,8 @@ static irqreturn_t aspeed_host_irq_handler(int irq, void *data) - - /*Change the CRT back to host*/ - regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, 0); -+ if ((priv->flags & CLK_MASK) == CLK_G7) -+ regmap_update_bits(priv->scu1, 0xD0, BIT(10), 0); - } else if (reg & priv->pcie_int_h_to_l) { - dev_dbg(drm->dev, "pcie de-active.\n"); - /*Change the DP into host*/ -@@ -218,6 +220,8 @@ static irqreturn_t aspeed_host_irq_handler(int irq, void *data) - - /*Change the CRT into soc*/ - regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, priv->soc_crt_bit); -+ if ((priv->flags & CLK_MASK) == CLK_G7) -+ regmap_update_bits(priv->scu1, 0xD0, BIT(10), BIT(10)); - } - return IRQ_HANDLED; - } -@@ -276,7 +280,10 @@ static int aspeed_pcie_active_detect(struct drm_device *drm) - - static int aspeed_adaptor_detect(struct drm_device *drm) - { -+ struct platform_device *pdev = to_platform_device(drm->dev); - struct aspeed_gfx *priv = to_aspeed_gfx(drm); -+ struct device_node *np = pdev->dev.of_node; -+ - u32 dp_status_offset = 0, reg = 0; - - switch (priv->flags & CLK_MASK) { -@@ -333,6 +340,16 @@ static int aspeed_adaptor_detect(struct drm_device *drm) - regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); - } - -+ /* get the scu1 for DAC setting */ -+ priv->scu1 = syscon_regmap_lookup_by_phandle(np, "syscon_io"); -+ if (IS_ERR(priv->scu1)) { -+ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2700-scu1"); -+ if (IS_ERR(priv->scu1)) { -+ dev_err(drm->dev, "failed to find SCU1 regmap\n"); -+ return PTR_ERR(priv->scu1); -+ } -+ } -+ - break; - default: - priv->dp_support = 0x0; -diff --git a/drivers/i2c/busses/i2c-ast2600.c b/drivers/i2c/busses/i2c-ast2600.c -index b160080c9..e809d82d9 100644 ---- a/drivers/i2c/busses/i2c-ast2600.c -+++ b/drivers/i2c/busses/i2c-ast2600.c -@@ -55,6 +55,7 @@ - #define AST2600_I2CCG_DIV_CTRL 0xC6411208 - #define AST2700_I2CCG_DIV_CTRL 0xC6220904 - #define AST2700_MIN_AC_TIMING 12000 -+#define AST_DEFAULT_AC_TIMING 100000 - - /* 0x00 : I2CC Controller/Target Function Control Register */ - #define AST2600_I2CC_FUN_CTRL 0x00 -@@ -293,6 +294,13 @@ - - #define AST2600_I2C_TARGET_COUNT 0x3 - -+#define HIGH_MIN_DIV 100000000 -+#define STANDARD_HIGH_MIN_400NS 400 -+#define FAST_HIGH_MIN_60NS 60 -+#define FAST_PLUS_HIGH_MIN_26NS 26 -+ -+#define DATAHOLD_MAX_LEVEL 3 -+ - enum xfer_mode { - BYTE_MODE, - BUFF_MODE, -@@ -320,7 +328,7 @@ struct ast2600_i2c_bus { - struct i2c_timings timing_info; - struct completion cmd_complete; - struct i2c_msg *msgs; -- u8 *controller_safe_buf; -+ u8 *controller_dma_buf; - dma_addr_t controller_dma_addr; - u32 apb_clk; - struct i2c_divisor clk_divisor; -@@ -336,6 +344,8 @@ struct ast2600_i2c_bus { - enum i2c_version version; - bool multi_master; - u32 debounce_level; -+ u32 manual_min_high; -+ u32 manual_data_hold; - /* Buffer mode */ - void __iomem *buf_base; - /* smbus alert */ -@@ -353,15 +363,40 @@ struct ast2600_i2c_bus { - #endif - }; - -+static u32 i2c_cal_high_min_config(struct ast2600_i2c_bus *i2c_bus, u64 base_clk) -+{ -+ u64 cal, spec_high_min = STANDARD_HIGH_MIN_400NS; -+ -+ /* fill the spec high min value */ -+ if (i2c_bus->timing_info.bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ && -+ i2c_bus->timing_info.bus_freq_hz > I2C_MAX_STANDARD_MODE_FREQ) -+ spec_high_min = FAST_HIGH_MIN_60NS; -+ else if (i2c_bus->timing_info.bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ && -+ i2c_bus->timing_info.bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) -+ spec_high_min = FAST_PLUS_HIGH_MIN_26NS; -+ -+ /* round down high minimum value to minimize the impact on the clock high time */ -+ cal = base_clk * spec_high_min; -+ return (u32)DIV_ROUND_DOWN_ULL(cal, HIGH_MIN_DIV); -+} -+ - static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - { - unsigned long base_clk[16]; - int baseclk_idx = 0; - int divisor = 0; - u32 clk_div_reg; -- u32 scl_low; -- u32 scl_high; -- u32 data; -+ u32 scl_low = 0; -+ u32 scl_high = 0; -+ u32 scl_high_min = 0; -+ u32 sda_data_hold = 0; -+ u32 data = 0; -+ -+ /* Check the maxmum i2c bus frequency */ -+ if (i2c_bus->timing_info.bus_freq_hz > I2C_MAX_ULTRA_FAST_MODE_FREQ) { -+ dev_err(i2c_bus->dev, "The frequency over spec. Set to 100KHz.\n"); -+ i2c_bus->timing_info.bus_freq_hz = AST_DEFAULT_AC_TIMING; -+ } - - regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); - -@@ -376,6 +411,9 @@ static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - if ((base_clk[i] / i2c_bus->timing_info.bus_freq_hz) <= 32) { - baseclk_idx = i; - divisor = DIV_ROUND_UP(base_clk[i], i2c_bus->timing_info.bus_freq_hz); -+ /* calculate the high min value */ -+ scl_high_min = i2c_cal_high_min_config(i2c_bus, (u64)base_clk[i]); -+ dev_dbg(i2c_bus->dev, "scl_high_min: %d\n", scl_high_min); - break; - } - } -@@ -384,13 +422,32 @@ static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - divisor = min(divisor, 32); - scl_low = min(divisor * 9 / 16 - 1, 15); - scl_high = (divisor - scl_low - 2) & GENMASK(3, 0); -- data = (scl_high - 1) << 20 | scl_high << 16 | scl_low << 12 | baseclk_idx; -+ -+ if (i2c_bus->manual_min_high) { -+ if (i2c_bus->manual_min_high > scl_high) -+ dev_info(i2c_bus->dev, "invalid manual high min: %d\n", -+ i2c_bus->manual_min_high); -+ else -+ scl_high_min = i2c_bus->manual_min_high; -+ } -+ -+ if (i2c_bus->manual_data_hold) { -+ if (i2c_bus->manual_data_hold > DATAHOLD_MAX_LEVEL) -+ dev_info(i2c_bus->dev, "invalid manual data hold: %d\n", -+ i2c_bus->manual_data_hold); -+ else -+ sda_data_hold = i2c_bus->manual_data_hold; -+ } -+ -+ data = baseclk_idx; -+ data |= scl_high_min << 20 | scl_high << 16 | scl_low << 12 | sda_data_hold << 10; - - if (i2c_bus->timeout) { - i2c_bus->timeout = min(i2c_bus->timeout, 31); - data |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout); - data |= AST2600_I2CC_TOUTBASECLK(AST2600_I2C_TIMEOUT_CLK); - } -+ dev_dbg(i2c_bus->dev, "ac: 0x%x\n", data); - - writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); - } -@@ -400,14 +457,20 @@ static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - unsigned long base_clk; - int baseclk_idx = 0; - int divisor = 0; -- u32 clk_div_reg; -- u32 scl_low; -- u32 scl_high; -- u32 data; -+ u32 clk_div_reg = 0; -+ u32 scl_low = 0; -+ u32 scl_high = 0; -+ u32 scl_high_min = 0; -+ u32 sda_data_hold = 0; -+ u32 data = 0; - u8 divid_term = 0; - -+ /* Check the maxmum i2c bus frequency */ - /* The i2c minmum ac-timing is 12KHz */ -- if (i2c_bus->timing_info.bus_freq_hz < AST2700_MIN_AC_TIMING) { -+ if (i2c_bus->timing_info.bus_freq_hz > I2C_MAX_ULTRA_FAST_MODE_FREQ) { -+ dev_err(i2c_bus->dev, "The frequency over spec. Set to 100KHz.\n"); -+ i2c_bus->timing_info.bus_freq_hz = AST_DEFAULT_AC_TIMING; -+ } else if (i2c_bus->timing_info.bus_freq_hz < AST2700_MIN_AC_TIMING) { - dev_err(i2c_bus->dev, "The frequency could not be lower than 12KHz.\n"); - i2c_bus->timing_info.bus_freq_hz = AST2700_MIN_AC_TIMING; - } -@@ -437,11 +500,35 @@ static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - } - } - -+ /* calculate the high min value */ -+ scl_high_min = i2c_cal_high_min_config(i2c_bus, (u64)base_clk); -+ dev_dbg(i2c_bus->dev, "scl_high_min: %d\n", scl_high_min); -+ - baseclk_idx = min(baseclk_idx, 0xff); - divisor = min(divisor, 32); - scl_low = min((DIV_ROUND_UP(divisor * 9, 16)) - 1, 15); - scl_high = (divisor - scl_low - 2) & GENMASK(3, 0); -- data = (scl_high - 1) << 20 | scl_high << 16 | scl_low << 12 | baseclk_idx; -+ -+ /* fill manual min high value */ -+ if (i2c_bus->manual_min_high) { -+ if (i2c_bus->manual_min_high > scl_high) -+ dev_info(i2c_bus->dev, -+ "invalid manual high min: %d\n", i2c_bus->manual_min_high); -+ else -+ scl_high_min = i2c_bus->manual_min_high; -+ } -+ -+ /* fill manual sda hold value */ -+ if (i2c_bus->manual_data_hold) { -+ if (i2c_bus->manual_data_hold > DATAHOLD_MAX_LEVEL) -+ dev_info(i2c_bus->dev, -+ "invalid manual data hold: %d\n", i2c_bus->manual_data_hold); -+ else -+ sda_data_hold = i2c_bus->manual_data_hold; -+ } -+ -+ data = baseclk_idx; -+ data |= scl_high_min << 20 | scl_high << 16 | scl_low << 12 | sda_data_hold << 10; - - if (i2c_bus->timeout) { - i2c_bus->timeout = min(i2c_bus->timeout, 255); -@@ -450,6 +537,7 @@ static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - /* timeout_base set as 1ms */ - data |= AST2600_I2CC_TOUTBASECLK(AST2700_I2C_TIMEOUT_CLK); - } -+ dev_dbg(i2c_bus->dev, "ac: 0x%x\n", data); - - writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); - } -@@ -457,11 +545,17 @@ static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) - static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus) - { - u32 state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ u32 ctrl; - int ret = 0; - int r; - - dev_dbg(i2c_bus->dev, "%d-bus recovery bus [%x]\n", i2c_bus->adap.nr, state); - -+ /* reset i2c controller to avoid the bus getting stuck */ -+ ctrl = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(ctrl & ~AST2600_I2CC_MASTER_EN, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ - reinit_completion(&i2c_bus->cmd_complete); - i2c_bus->cmd_err = 0; - -@@ -539,11 +633,12 @@ static void ast2700_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u - i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); - writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); - /* clear sirq log */ -- while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) { -+ while ((sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG))) { - /* assign the target client*/ - if (sirq_log & SADDR_HIT) { - if (!i2c_bus->target) -- ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ ast2700_i2c_get_target(i2c_bus, -+ sirq_log >> SLAVE_ADDR_SHIFT); - } - }; - writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); -@@ -561,11 +656,12 @@ static void ast2700_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u - i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); - writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); - /* clear sirq log */ -- while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) { -+ while ((sirq_log = readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG))) { - /* assign the target client*/ - if (sirq_log & SADDR_HIT) { - if (!i2c_bus->target) -- ast2700_i2c_get_target(i2c_bus, sirq_log >> SLAVE_ADDR_SHIFT); -+ ast2700_i2c_get_target(i2c_bus, -+ sirq_log >> SLAVE_ADDR_SHIFT); - } - }; - writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); -@@ -1391,7 +1487,6 @@ static int ast2600_i2c_setup_dma_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) - { - struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; - int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; -- int ret; - - cmd |= AST2600_I2CM_PKT_EN; - -@@ -1400,32 +1495,14 @@ static int ast2600_i2c_setup_dma_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) - else if (i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) - cmd |= AST2600_I2CM_STOP_CMD; - -- if (cmd & AST2600_I2CM_START_CMD) { -+ if (cmd & AST2600_I2CM_START_CMD) - cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); -- if (xfer_len) { -- i2c_bus->controller_safe_buf = i2c_get_dma_safe_msg_buf(msg, 1); -- if (!i2c_bus->controller_safe_buf) -- return -ENOMEM; -- i2c_bus->controller_dma_addr = -- dma_map_single(i2c_bus->dev, i2c_bus->controller_safe_buf, -- msg->len, DMA_TO_DEVICE); -- ret = dma_mapping_error(i2c_bus->dev, i2c_bus->controller_dma_addr); -- if (ret) { -- i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, false); -- i2c_bus->controller_safe_buf = NULL; -- return ret; -- } -- } -- } - - if (xfer_len) { -+ memcpy(i2c_bus->controller_dma_buf, msg->buf, xfer_len); - cmd |= AST2600_I2CM_TX_DMA_EN | AST2600_I2CM_TX_CMD; - writel(AST2600_I2CM_SET_TX_DMA_LEN(xfer_len - 1), - i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); -- writel(lower_32_bits(i2c_bus->controller_dma_addr), -- i2c_bus->reg_base + AST2600_I2CM_TX_DMA); -- writel(upper_32_bits(i2c_bus->controller_dma_addr), -- i2c_bus->reg_base + AST2600_I2CM_TX_DMA_H); - } - - writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); -@@ -1458,7 +1535,7 @@ static int ast2600_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) - * and write the remaining unaligned data at the end. - */ - if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -- return -ENOMEM; -+ return -EBUSY; - for (i = 0; i < xfer_len; i += 4) { - int xfer_cnt = i2c_bus->controller_xfer_cnt + i; - -@@ -1479,13 +1556,13 @@ static int ast2600_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) - writel(wbuf_dword, i2c_bus->buf_base + i); - } - if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -- return -ENOMEM; -+ return -EBUSY; - writel(AST2600_I2CC_SET_TX_BUF_LEN(xfer_len), - i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); - } - - if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -- return -ENOMEM; -+ return -EBUSY; - - writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); - -@@ -1523,7 +1600,6 @@ static int ast2600_i2c_setup_dma_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) - { - struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; - int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; -- int ret; - - cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_DMA_EN | AST2600_I2CM_RX_CMD; - -@@ -1538,33 +1614,8 @@ static int ast2600_i2c_setup_dma_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) - - writel(AST2600_I2CM_SET_RX_DMA_LEN(xfer_len - 1), i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); - -- if (cmd & AST2600_I2CM_START_CMD) { -+ if (cmd & AST2600_I2CM_START_CMD) - cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); -- i2c_bus->controller_safe_buf = i2c_get_dma_safe_msg_buf(msg, 1); -- if (!i2c_bus->controller_safe_buf) -- return -ENOMEM; -- if (msg->flags & I2C_M_RECV_LEN) -- i2c_bus->controller_dma_addr = -- dma_map_single(i2c_bus->dev, i2c_bus->controller_safe_buf, -- I2C_SMBUS_BLOCK_MAX + 3, DMA_FROM_DEVICE); -- else -- i2c_bus->controller_dma_addr = -- dma_map_single(i2c_bus->dev, i2c_bus->controller_safe_buf, -- msg->len, DMA_FROM_DEVICE); -- ret = dma_mapping_error(i2c_bus->dev, i2c_bus->controller_dma_addr); -- if (ret) { -- i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, false); -- i2c_bus->controller_safe_buf = NULL; -- return -ENOMEM; -- } -- } -- -- writel(lower_32_bits(i2c_bus->controller_dma_addr + -- i2c_bus->controller_xfer_cnt), -- i2c_bus->reg_base + AST2600_I2CM_RX_DMA); -- writel(upper_32_bits(i2c_bus->controller_dma_addr + -- i2c_bus->controller_xfer_cnt), -- i2c_bus->reg_base + AST2600_I2CM_RX_DMA_H); - - writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); - -@@ -1701,7 +1752,7 @@ static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, - i2c_bus->msgs_index++; - if (i2c_bus->msgs_index < i2c_bus->msgs_count) { - if (ast2600_i2c_do_start(i2c_bus)) { -- i2c_bus->cmd_err = -ENOMEM; -+ i2c_bus->cmd_err = -EBUSY; - complete(&i2c_bus->cmd_complete); - } - } else { -@@ -1711,31 +1762,26 @@ static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, - break; - case AST2600_I2CM_TX_ACK: - case AST2600_I2CM_TX_ACK | AST2600_I2CM_NORMAL_STOP: -- if (i2c_bus->mode == DMA_MODE) -+ if (i2c_bus->mode == DMA_MODE) { - xfer_len = AST2600_I2C_GET_TX_DMA_LEN(readl(i2c_bus->reg_base + -- AST2600_I2CM_DMA_LEN_STS)); -- else if (i2c_bus->mode == BUFF_MODE) -+ AST2600_I2CM_DMA_LEN_STS)); -+ } else if (i2c_bus->mode == BUFF_MODE) { - xfer_len = AST2600_I2CC_GET_TX_BUF_LEN(readl(i2c_bus->reg_base + - AST2600_I2CC_BUFF_CTRL)); -- else -+ } else { - xfer_len = 1; -+ } - - i2c_bus->controller_xfer_cnt += xfer_len; - - if (i2c_bus->controller_xfer_cnt == msg->len) { -- if (i2c_bus->mode == DMA_MODE) { -- dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -- DMA_TO_DEVICE); -- i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, true); -- i2c_bus->controller_safe_buf = NULL; -- } - i2c_bus->msgs_index++; - if (i2c_bus->msgs_index == i2c_bus->msgs_count) { - i2c_bus->cmd_err = i2c_bus->msgs_index; - complete(&i2c_bus->cmd_complete); - } else { - if (ast2600_i2c_do_start(i2c_bus)) { -- i2c_bus->cmd_err = -ENOMEM; -+ i2c_bus->cmd_err = -EBUSY; - complete(&i2c_bus->cmd_complete); - } - } -@@ -1768,6 +1814,8 @@ static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, - if (i2c_bus->mode == DMA_MODE) { - xfer_len = AST2600_I2C_GET_RX_DMA_LEN(readl(i2c_bus->reg_base + - AST2600_I2CM_DMA_LEN_STS)); -+ memcpy(&msg->buf[i2c_bus->controller_xfer_cnt], -+ i2c_bus->controller_dma_buf, xfer_len); - } else if (i2c_bus->mode == BUFF_MODE) { - xfer_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base + - AST2600_I2CC_BUFF_CTRL)); -@@ -1804,20 +1852,13 @@ static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, - } - - if (i2c_bus->controller_xfer_cnt == msg->len) { -- if (i2c_bus->mode == DMA_MODE) { -- dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -- DMA_FROM_DEVICE); -- i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, true); -- i2c_bus->controller_safe_buf = NULL; -- } -- - i2c_bus->msgs_index++; - if (i2c_bus->msgs_index == i2c_bus->msgs_count) { - i2c_bus->cmd_err = i2c_bus->msgs_index; - complete(&i2c_bus->cmd_complete); - } else { - if (ast2600_i2c_do_start(i2c_bus)) { -- i2c_bus->cmd_err = -ENOMEM; -+ i2c_bus->cmd_err = -EBUSY; - complete(&i2c_bus->cmd_complete); - } - } -@@ -1962,36 +2003,12 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg - dev_dbg(i2c_bus->dev, "timeout isr[%x], sts[%x]\n", - readl(i2c_bus->reg_base + AST2600_I2CM_ISR), - readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF)); -- writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(ctrl & ~AST2600_I2CC_MASTER_EN, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); - writel(ctrl, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -- if (i2c_bus->multi_master && -+ if (i2c_bus->multi_master && !i2c_bus->target_operate && - (readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) & - AST2600_I2CC_BUS_BUSY_STS)) - ast2600_i2c_recover_bus(i2c_bus); --#if IS_ENABLED(CONFIG_I2C_SLAVE) -- if (ctrl & AST2600_I2CC_SLAVE_EN) { -- u32 cmd = TARGET_TRIGGER_CMD; -- -- if (i2c_bus->mode == DMA_MODE) { -- cmd |= AST2600_I2CS_RX_DMA_EN; -- writel(lower_32_bits(i2c_bus->target_dma_addr), -- i2c_bus->reg_base + AST2600_I2CS_RX_DMA); -- writel(upper_32_bits(i2c_bus->target_dma_addr), -- i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); -- writel(lower_32_bits(i2c_bus->target_dma_addr), -- i2c_bus->reg_base + AST2600_I2CS_TX_DMA); -- writel(upper_32_bits(i2c_bus->target_dma_addr), -- i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); -- writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), -- i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); -- } else if (i2c_bus->mode == BUFF_MODE) { -- cmd = TARGET_TRIGGER_CMD; -- } else { -- cmd &= ~AST2600_I2CS_PKT_MODE_EN; -- } -- writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -- } --#endif - ret = -ETIMEDOUT; - } else { - ret = i2c_bus->cmd_err; -@@ -2000,26 +2017,10 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg - dev_dbg(i2c_bus->dev, "bus%d-m: %d end\n", i2c_bus->adap.nr, i2c_bus->cmd_err); - - controller_out: -- if (i2c_bus->mode == DMA_MODE) { -- /* still have controller_safe_buf need to be released */ -- if (i2c_bus->controller_safe_buf) { -- struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -- -- if (msg->flags & I2C_M_RD) -- dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -- DMA_FROM_DEVICE); -- else -- dma_unmap_single(i2c_bus->dev, i2c_bus->controller_dma_addr, msg->len, -- DMA_TO_DEVICE); -- i2c_put_dma_safe_msg_buf(i2c_bus->controller_safe_buf, msg, true); -- i2c_bus->controller_safe_buf = NULL; -- } -- } -- - return ret; - } - --static void ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) -+static int ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) - { - struct platform_device *pdev = to_platform_device(i2c_bus->dev); - u32 fun_ctrl = AST2600_I2CC_BUS_AUTO_RELEASE | AST2600_I2CC_MASTER_EN; -@@ -2031,6 +2032,16 @@ static void ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) - if (!i2c_bus->multi_master) - fun_ctrl |= AST2600_I2CC_MULTI_MASTER_DIS; - -+ /* I2C manual minimum SCL high */ -+ if (device_property_read_u32(&pdev->dev, "manual-min-high", -+ &i2c_bus->manual_min_high)) -+ i2c_bus->manual_min_high = 0; -+ -+ /* I2C manual data hold */ -+ if (device_property_read_u32(&pdev->dev, "manual-data-hold", -+ &i2c_bus->manual_data_hold)) -+ i2c_bus->manual_data_hold = 0; -+ - /* I2C Debounce level */ - if (i2c_bus->version != AST2600) { - if (!device_property_read_u32(&pdev->dev, "debounce-level", -@@ -2066,6 +2077,22 @@ static void ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) - else - ast2600_i2c_ac_timing_config(i2c_bus); - -+ if (i2c_bus->mode == DMA_MODE) { -+ i2c_bus->controller_dma_buf = -+ dmam_alloc_coherent(i2c_bus->dev, AST2600_I2C_DMA_SIZE, -+ &i2c_bus->controller_dma_addr, GFP_KERNEL); -+ if (!i2c_bus->controller_dma_buf) -+ return -ENOMEM; -+ writel(lower_32_bits(i2c_bus->controller_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CM_TX_DMA); -+ writel(upper_32_bits(i2c_bus->controller_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CM_TX_DMA_H); -+ writel(lower_32_bits(i2c_bus->controller_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CM_RX_DMA); -+ writel(upper_32_bits(i2c_bus->controller_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CM_RX_DMA_H); -+ } -+ - /* Clear Interrupt */ - writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR); - -@@ -2076,7 +2103,7 @@ static void ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) - dmam_alloc_coherent(i2c_bus->dev, I2C_TARGET_MSG_BUF_SIZE, - &i2c_bus->target_dma_addr, GFP_KERNEL); - if (!i2c_bus->target_dma_buf) -- return; -+ return -ENOMEM; - } - - writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CS_ISR); -@@ -2086,6 +2113,8 @@ static void ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) - else - writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); - #endif -+ -+ return 0; - } - - #if IS_ENABLED(CONFIG_I2C_SLAVE) -@@ -2106,7 +2135,8 @@ static int ast2600_i2c_reg_target(struct i2c_client *client) - for (i = 0; i < AST2600_I2C_TARGET_COUNT; i++) { - if (i2c_bus->multi_target[i]) { - if (i2c_bus->multi_target[i]->addr == client->addr) { -- dev_dbg(i2c_bus->dev, "duplicate address [%x] on %d\n", client->addr, i); -+ dev_dbg(i2c_bus->dev, "duplicate address [%x] on %d\n", -+ client->addr, i); - return -EINVAL; - } - } -@@ -2159,14 +2189,20 @@ static int ast2600_i2c_reg_target(struct i2c_client *client) - /* trigger rx buffer */ - if (i2c_bus->mode == DMA_MODE) { - cmd |= AST2600_I2CS_RX_DMA_EN; -- writel(lower_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_RX_DMA); -- writel(upper_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); -- writel(lower_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_TX_DMA); -- writel(upper_32_bits(i2c_bus->target_dma_addr), i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); -+ writel(lower_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_RX_DMA); -+ writel(upper_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_RX_DMA_H); -+ writel(lower_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_TX_DMA); -+ writel(upper_32_bits(i2c_bus->target_dma_addr), -+ i2c_bus->reg_base + AST2600_I2CS_TX_DMA_H); - writel(AST2600_I2CS_SET_RX_DMA_LEN(I2C_TARGET_MSG_BUF_SIZE), - i2c_bus->reg_base + AST2600_I2CS_DMA_LEN); - } else if (i2c_bus->mode == BUFF_MODE) { - cmd = TARGET_TRIGGER_CMD; -+ if (i2c_bus->version == AST2700) -+ cmd |= AST2600_I2CS_RX_DMA_EN; - } else { - cmd &= ~AST2600_I2CS_PKT_MODE_EN; - } -@@ -2195,20 +2231,8 @@ static int ast2600_i2c_unreg_target(struct i2c_client *client) - i2c_bus->multi_target[i] = NULL; - target_unreg = true; - dev_dbg(i2c_bus->dev, "un-reg [%x] from %d\n", client->addr, i); -- - /* remove target addr by index */ -- switch (i) { -- case 0: -- target_addr &= ~(AST2600_I2CS_ADDR1_MASK | AST2600_I2CS_ADDR1_ENABLE); -- break; -- case 1: -- target_addr &= ~(AST2600_I2CS_ADDR2_MASK | AST2600_I2CS_ADDR2_ENABLE); -- break; -- case 2: -- target_addr &= ~(AST2600_I2CS_ADDR3_MASK | AST2600_I2CS_ADDR3_ENABLE); -- break; -- } -- -+ target_addr &= ~(0xff << 8 * i); - writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); - break; - } -@@ -2279,9 +2303,11 @@ static int ast2600_i2c_probe(struct platform_device *pdev) - if ((global_ctrl & AST2600_GLOBAL_INIT) != AST2600_GLOBAL_INIT) { - regmap_write(i2c_bus->global_regs, AST2600_I2CG_CTRL, AST2600_GLOBAL_INIT); - if (i2c_bus->version == AST2600) -- regmap_write(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, AST2600_I2CCG_DIV_CTRL); -+ regmap_write(i2c_bus->global_regs, -+ AST2600_I2CG_CLK_DIV_CTRL, AST2600_I2CCG_DIV_CTRL); - else -- regmap_write(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, AST2700_I2CCG_DIV_CTRL); -+ regmap_write(i2c_bus->global_regs, -+ AST2600_I2CG_CLK_DIV_CTRL, AST2700_I2CCG_DIV_CTRL); - } - - #if IS_ENABLED(CONFIG_I2C_SLAVE) -@@ -2354,7 +2380,9 @@ static int ast2600_i2c_probe(struct platform_device *pdev) - i2c_set_adapdata(&i2c_bus->adap, i2c_bus); - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); - -- ast2600_i2c_init(i2c_bus); -+ ret = ast2600_i2c_init(i2c_bus); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "Unable to initial i2c %d\n", ret); - - ret = devm_request_irq(dev, i2c_bus->irq, ast2600_i2c_bus_irq, 0, - dev_name(dev), i2c_bus); -diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile -index 39c39a0fa..95e13a5b2 100644 ---- a/drivers/irqchip/Makefile -+++ b/drivers/irqchip/Makefile -@@ -84,7 +84,8 @@ obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o - obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o - obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o - obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o irq-aspeed-intc.o irq-aspeed-e2m-ic.o -+obj-$(CONFIG_AST2700_IRQ) += irq-ast2700-intc0.o irq-ast2700-intc1.o - obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o - obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o - obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o - obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o -diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc.c -index d0ba0dc0b..8fa6b583f 100644 ---- a/drivers/irqchip/irq-aspeed-intc.c -+++ b/drivers/irqchip/irq-aspeed-intc.c -@@ -87,7 +87,7 @@ static void aspeed_intc_irq_mask(struct irq_data *data) - struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); - unsigned int mask; - -- guard(raw_spinlock)(&intc_ic->intc_lock); -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); - mask = readl(intc_ic->base + INTC_INT_ENABLE_REG) & ~BIT(data->hwirq); - writel(mask, intc_ic->base + INTC_INT_ENABLE_REG); - } -@@ -97,7 +97,7 @@ static void aspeed_intc_irq_unmask(struct irq_data *data) - struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); - unsigned int unmask; - -- guard(raw_spinlock)(&intc_ic->intc_lock); -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); - unmask = readl(intc_ic->base + INTC_INT_ENABLE_REG) | BIT(data->hwirq); - writel(unmask, intc_ic->base + INTC_INT_ENABLE_REG); - } -diff --git a/drivers/irqchip/irq-ast2700-intc0.c b/drivers/irqchip/irq-ast2700-intc0.c -new file mode 100644 -index 000000000..48d61505a ---- /dev/null -+++ b/drivers/irqchip/irq-ast2700-intc0.c -@@ -0,0 +1,509 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Aspeed Interrupt Controller. -+ * -+ * Copyright (C) 2023 ASPEED Technology Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define INT_NUM 480 -+#define SWINT_NUM 16 -+#define INTM_NUM 50 -+ -+#define SWINT_BASE (INT_NUM) -+#define INTM_BASE (INT_NUM + SWINT_NUM) -+#define INT0_NUM (INT_NUM + SWINT_NUM + INTM_NUM) -+ -+#define GIC_P2P_SPI_END 128 -+#define GIC_SWINT_SPI_BASE 144 -+#define GIC_SWINT_SPI_NUM 16 -+#define GIC_INTM_SPI_BASE 192 -+ -+#define INTC0_SWINT_IER 0x10 -+#define INTC0_SWINT_ISR 0x14 -+#define INTC0_INTBANKX_IER 0x1000 -+#define INTC0_INTBANK_GROUPS 11 -+#define INTC0_INTBANKS_PER_GRP 3 -+#define INTC0_IMTMX_IER 0x1b00 -+#define INTC0_IMTMX_ISR 0x1b04 -+#define INTC0_IMTM_BANK_NUM 3 -+#define INTM_IRQS_PER_BANK 10 -+ -+struct intc0_pin_region { -+ u32 int_base; -+ u32 gic_base; -+ u32 cnt; -+}; -+ -+struct aspeed_intc_ic { -+ void __iomem *base; -+ raw_spinlock_t intc_lock; -+ struct irq_domain *irq_domain; -+ struct intc0_pin_region *pin_region; -+ int pin_region_cnt; -+}; -+ -+static void aspeed_swint_irq_mask(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bit = data->hwirq - SWINT_BASE; -+ unsigned int mask; -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ mask = readl(intc_ic->base + INTC0_SWINT_IER) & ~BIT(bit); -+ writel(mask, intc_ic->base + INTC0_SWINT_IER); -+ irq_chip_mask_parent(data); -+} -+ -+static void aspeed_swint_irq_unmask(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bit = data->hwirq - SWINT_BASE; -+ unsigned int unmask; -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ unmask = readl(intc_ic->base + INTC0_SWINT_IER) | BIT(bit); -+ writel(unmask, intc_ic->base + INTC0_SWINT_IER); -+ irq_chip_unmask_parent(data); -+} -+ -+static void aspeed_swint_irq_eoi(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bit = data->hwirq - SWINT_BASE; -+ -+ writel(BIT(bit), intc_ic->base + INTC0_SWINT_ISR); -+ irq_chip_eoi_parent(data); -+} -+ -+static struct irq_chip aspeed_swint_chip = { -+ .name = "ast2700-swint", -+ .irq_eoi = aspeed_swint_irq_eoi, -+ .irq_mask = aspeed_swint_irq_mask, -+ .irq_unmask = aspeed_swint_irq_unmask, -+ .irq_set_affinity = irq_chip_set_affinity_parent, -+ .flags = IRQCHIP_SET_TYPE_MASKED, -+}; -+ -+static void aspeed_intc0_irq_mask(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK; -+ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK; -+ unsigned int mask; -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ mask = readl(intc_ic->base + INTC0_IMTMX_IER + bank * 0x10) & ~BIT(bit); -+ writel(mask, intc_ic->base + INTC0_IMTMX_IER + bank * 0x10); -+ irq_chip_mask_parent(data); -+} -+ -+static void aspeed_intc0_irq_unmask(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK; -+ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK; -+ unsigned int unmask; -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ unmask = readl(intc_ic->base + INTC0_IMTMX_IER + bank * 0x10) | BIT(bit); -+ writel(unmask, intc_ic->base + INTC0_IMTMX_IER + bank * 0x10); -+ irq_chip_unmask_parent(data); -+} -+ -+static void aspeed_intc0_irq_eoi(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK; -+ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK; -+ -+ /* -+ * TODO: This a WA to prevnet potential race conditions when -+ * multiple interrupts are processed in multi-core environment. -+ */ -+ raw_spin_lock(&intc_ic->intc_lock); -+ writel(BIT(bit), intc_ic->base + INTC0_IMTMX_ISR + bank * 0x10); -+ raw_spin_unlock(&intc_ic->intc_lock); -+ -+ irq_chip_eoi_parent(data); -+} -+ -+static struct irq_chip aspeed_intm_chip = { -+ .name = "ast2700-intmerge", -+ .irq_eoi = aspeed_intc0_irq_eoi, -+ .irq_mask = aspeed_intc0_irq_mask, -+ .irq_unmask = aspeed_intc0_irq_unmask, -+ .irq_set_affinity = irq_chip_set_affinity_parent, -+ .flags = IRQCHIP_SET_TYPE_MASKED, -+ -+}; -+ -+static struct irq_chip linear_intr_irq_chip = { -+ .name = "ast2700-int", -+ .irq_eoi = irq_chip_eoi_parent, -+ .irq_mask = irq_chip_mask_parent, -+ .irq_unmask = irq_chip_unmask_parent, -+ .irq_set_affinity = irq_chip_set_affinity_parent, -+ .flags = IRQCHIP_SET_TYPE_MASKED, -+}; -+ -+static int aspeed_intc_ic0_map_irq_domain(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) -+{ -+ if (hwirq < GIC_P2P_SPI_END) -+ irq_set_chip_and_handler(irq, &linear_intr_irq_chip, handle_level_irq); -+ else if (hwirq < SWINT_BASE) -+ return -EINVAL; -+ else if (hwirq < INTM_BASE) -+ irq_set_chip_and_handler(irq, &aspeed_swint_chip, handle_level_irq); -+ else if (hwirq < INT0_NUM) -+ irq_set_chip_and_handler(irq, &aspeed_intm_chip, handle_level_irq); -+ else -+ return -EINVAL; -+ -+ irq_set_chip_data(irq, domain->host_data); -+ return 0; -+} -+ -+static int aspeed_intc0_irq_domain_translate(struct irq_domain *domain, -+ struct irq_fwspec *fwspec, -+ unsigned long *hwirq, -+ unsigned int *type) -+{ -+ if (fwspec->param_count != 1) -+ return -EINVAL; -+ -+ *hwirq = fwspec->param[0]; -+ *type = IRQ_TYPE_NONE; -+ return 0; -+} -+ -+static int get_parent_hwirq(struct aspeed_intc_ic *intc_ic, -+ u32 local_hwirq, -+ irq_hw_number_t *parent_hwirq) -+{ -+ int i; -+ -+ for (i = 0; i < intc_ic->pin_region_cnt; i++) { -+ u32 int_base = intc_ic->pin_region[i].int_base; -+ u32 cnt = intc_ic->pin_region[i].cnt; -+ -+ if (local_hwirq >= int_base && local_hwirq < int_base + cnt) { -+ *parent_hwirq = intc_ic->pin_region[i].gic_base + -+ (local_hwirq - int_base); -+ return 0; -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+static int aspeed_intc0_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, -+ unsigned int nr_irqs, void *data) -+{ -+ struct aspeed_intc_ic *intc_ic = domain->host_data; -+ struct irq_fwspec *fwspec = data; -+ struct irq_fwspec parent_fwspec; -+ irq_hw_number_t parent_hwirq; -+ struct irq_chip *chip; -+ unsigned long hwirq; -+ unsigned int type; -+ int ret; -+ -+ ret = aspeed_intc0_irq_domain_translate(domain, fwspec, &hwirq, &type); -+ if (ret) -+ return ret; -+ -+ if (hwirq >= GIC_P2P_SPI_END && hwirq < INT_NUM) -+ return -EINVAL; -+ -+ if (hwirq < SWINT_BASE) -+ chip = &linear_intr_irq_chip; -+ else if (hwirq < INTM_BASE) -+ chip = &aspeed_swint_chip; -+ else -+ chip = &aspeed_intm_chip; -+ -+ ret = get_parent_hwirq(intc_ic, (u32)hwirq, &parent_hwirq); -+ if (ret) -+ return irq_domain_disconnect_hierarchy(domain->parent, virq); -+ -+ parent_fwspec.fwnode = domain->parent->fwnode; -+ parent_fwspec.param_count = 3; -+ parent_fwspec.param[0] = GIC_SPI; -+ parent_fwspec.param[1] = parent_hwirq; -+ parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; -+ -+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); -+ if (ret) -+ return ret; -+ -+ for (int i = 0; i < nr_irqs; ++i, ++hwirq, ++virq) { -+ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, -+ chip, -+ domain->host_data); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int aspeed_intc0_irq_domain_activate(struct irq_domain *domain, -+ struct irq_data *data, bool reserve) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ -+ if (data->hwirq < GIC_P2P_SPI_END) { -+ int bank = data->hwirq / 32; -+ int bit = data->hwirq % 32; -+ u32 mask = BIT(bit); -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ for (int i = 0; i < 3; i++) { -+ void __iomem *sel = intc_ic->base + 0x200 + bank * 4 + 0x100 * i; -+ -+ if (readl(sel) & mask) { -+ writel(readl(sel) & ~mask, sel); -+ if (readl(sel) & mask) -+ return -EACCES; -+ } -+ } -+ } else if (data->hwirq < INT_NUM) { -+ return -EINVAL; -+ } else if (data->hwirq < INT0_NUM) { -+ return 0; -+ } else { -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops aspeed_intc0_ic_irq_domain_ops = { -+ .translate = aspeed_intc0_irq_domain_translate, -+ .alloc = aspeed_intc0_irq_domain_alloc, -+ .free = irq_domain_free_irqs_common, -+ .map = aspeed_intc_ic0_map_irq_domain, -+ .activate = aspeed_intc0_irq_domain_activate, -+}; -+ -+static int aspeed_intc0_init_gic_ranges(struct aspeed_intc_ic *intc_ic, -+ struct device_node *node, -+ struct device_node *parent_node) -+{ -+ struct intc0_pin_region *pin_region; -+ int region_cnt = 0; -+ int i, n, ret; -+ -+ if (!of_device_is_compatible(parent_node, "arm,gic-v3")) -+ return -ENOENT; -+ -+ n = of_property_count_elems_of_size(node, "aspeed,interrupt-ranges", sizeof(u32)); -+ if (n <= 0 || n % 6) -+ return -EINVAL; -+ -+ /* -+ * Each range is described as: -+ * -+ * and we only care about ranges whose phandle matches -+ * this controller's interrupt-parent (&gic). -+ */ -+ for (i = 0; i < n / 6; i++) { -+ struct device_node *target; -+ phandle parent_handle; -+ u32 gic_type; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 2, &parent_handle); -+ if (ret) -+ return ret; -+ -+ target = of_find_node_by_phandle(parent_handle); -+ if (!target) -+ continue; -+ -+ if (target != parent_node) { -+ of_node_put(target); -+ continue; -+ } -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 3, &gic_type); -+ of_node_put(target); -+ if (ret) -+ return ret; -+ -+ if (gic_type != GIC_SPI) -+ continue; -+ -+ region_cnt++; -+ } -+ -+ if (!region_cnt) -+ return -EINVAL; -+ -+ pin_region = kcalloc(region_cnt, sizeof(*pin_region), GFP_KERNEL); -+ if (!pin_region) -+ return -ENOMEM; -+ -+ intc_ic->pin_region_cnt = region_cnt; -+ intc_ic->pin_region = pin_region; -+ -+ region_cnt = 0; -+ for (i = 0; i < n / 6; i++) { -+ struct device_node *target; -+ phandle parent_handle; -+ u32 gic_flags; -+ u32 gic_type; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 2, &parent_handle); -+ if (ret) -+ return ret; -+ -+ target = of_find_node_by_phandle(parent_handle); -+ if (!target) -+ continue; -+ -+ if (target != parent_node) { -+ of_node_put(target); -+ continue; -+ } -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 0, -+ &pin_region[region_cnt].int_base); -+ if (ret) -+ goto out_put; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 1, -+ &pin_region[region_cnt].cnt); -+ if (ret) -+ goto out_put; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 3, &gic_type); -+ if (ret) -+ goto out_put; -+ -+ if (gic_type != GIC_SPI) -+ goto out_put; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 4, -+ &pin_region[region_cnt].gic_base); -+ if (ret) -+ goto out_put; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 5, &gic_flags); -+ if (ret) -+ goto out_put; -+ -+ if (gic_flags != IRQ_TYPE_LEVEL_HIGH) -+ goto out_put; -+ -+ region_cnt++; -+out_put: -+ of_node_put(target); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void aspeed_intc0_disable_swint(struct aspeed_intc_ic *intc_ic) -+{ -+ writel(0, intc_ic->base + INTC0_SWINT_IER); -+} -+ -+static void aspeed_intc0_disable_intbank(struct aspeed_intc_ic *intc_ic) -+{ -+ int i, j; -+ -+ for (i = 0; i < INTC0_INTBANK_GROUPS; i++) { -+ for (j = 0; j < INTC0_INTBANKS_PER_GRP; j++) { -+ u32 base = INTC0_INTBANKX_IER + (0x100 * i) + (0x10 * j); -+ -+ writel(0, intc_ic->base + base); -+ } -+ } -+} -+ -+static void aspeed_intc0_disable_intm(struct aspeed_intc_ic *intc_ic) -+{ -+ int i; -+ -+ for (i = 0; i < INTC0_IMTM_BANK_NUM; i++) -+ writel(0, intc_ic->base + INTC0_IMTMX_IER + (0x10 * i)); -+} -+ -+static int aspeed_intc0_ic_of_init(struct device_node *node, struct device_node *parent) -+{ -+ struct irq_domain *parent_domain; -+ struct aspeed_intc_ic *intc_ic; -+ int ret; -+ -+ if (!parent) { -+ pr_err("missing parent interrupt node\n"); -+ return -ENODEV; -+ } -+ -+ intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); -+ if (!intc_ic) -+ return -ENOMEM; -+ -+ intc_ic->base = of_iomap(node, 0); -+ if (!intc_ic->base) { -+ ret = -ENOMEM; -+ goto err_free_ic; -+ } -+ -+ aspeed_intc0_disable_swint(intc_ic); -+ aspeed_intc0_disable_intbank(intc_ic); -+ aspeed_intc0_disable_intm(intc_ic); -+ -+ raw_spin_lock_init(&intc_ic->intc_lock); -+ -+ parent_domain = irq_find_host(parent); -+ if (!parent_domain) { -+ pr_err("unable to obtain parent domain\n"); -+ return -ENODEV; -+ } -+ -+ intc_ic->irq_domain = irq_domain_create_hierarchy(parent_domain, 0, INT0_NUM, -+ of_fwnode_handle(node), -+ &aspeed_intc0_ic_irq_domain_ops, -+ intc_ic); -+ if (!intc_ic->irq_domain) { -+ ret = -ENOMEM; -+ goto err_ioumap; -+ } -+ -+ ret = aspeed_intc0_init_gic_ranges(intc_ic, node, parent); -+ if (ret < 0) -+ goto err_ioumap; -+ -+ return 0; -+ -+err_ioumap: -+ iounmap(intc_ic->base); -+err_free_ic: -+ kfree(intc_ic); -+ return ret; -+} -+ -+IRQCHIP_DECLARE(ast2700_intc0_ic, "aspeed,ast2700-intc0-ic", aspeed_intc0_ic_of_init); -diff --git a/drivers/irqchip/irq-ast2700-intc1.c b/drivers/irqchip/irq-ast2700-intc1.c -new file mode 100644 -index 000000000..eac1bef21 ---- /dev/null -+++ b/drivers/irqchip/irq-ast2700-intc1.c -@@ -0,0 +1,254 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Aspeed Interrupt Controller. -+ * -+ * Copyright (C) 2023 ASPEED Technology Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define INTC1_IER 0x100 -+#define INTC1_ISR 0x104 -+#define INTC1_IRQS_PER_BANK 32 -+#define INTC1_BANK_NUM 6 -+ -+struct aspeed_intc_ic { -+ void __iomem *base; -+ raw_spinlock_t intc_lock; -+ struct irq_domain *irq_domain; -+}; -+ -+static void aspeed_intc1_ic_irq_handler(struct irq_desc *desc) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc); -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ unsigned long bit, status; -+ -+ chained_irq_enter(chip, desc); -+ -+ for (int bank = 0; bank < INTC1_BANK_NUM; bank++) { -+ status = readl(intc_ic->base + INTC1_ISR + (0x10 * bank)); -+ if (!status) -+ continue; -+ -+ for_each_set_bit(bit, &status, INTC1_IRQS_PER_BANK) { -+ generic_handle_domain_irq(intc_ic->irq_domain, -+ (bank * INTC1_IRQS_PER_BANK) + bit); -+ writel(BIT(bit), intc_ic->base + INTC1_ISR + (0x10 * bank)); -+ } -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static void aspeed_intc1_irq_mask(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bit = data->hwirq % INTC1_IRQS_PER_BANK; -+ int bank = data->hwirq / INTC1_IRQS_PER_BANK; -+ unsigned int mask; -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ mask = readl(intc_ic->base + INTC1_IER + (0x10 * bank)) & ~BIT(bit); -+ writel(mask, intc_ic->base + INTC1_IER + (0x10 * bank)); -+} -+ -+static void aspeed_intc1_irq_unmask(struct irq_data *data) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bit = data->hwirq % INTC1_IRQS_PER_BANK; -+ int bank = data->hwirq / INTC1_IRQS_PER_BANK; -+ unsigned int unmask; -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ unmask = readl(intc_ic->base + INTC1_IER + (0x10 * bank)) | BIT(bit); -+ writel(unmask, intc_ic->base + INTC1_IER + (0x10 * bank)); -+} -+ -+static struct irq_chip aspeed_intc_chip = { -+ .name = "ASPEED INTC1", -+ .irq_mask = aspeed_intc1_irq_mask, -+ .irq_unmask = aspeed_intc1_irq_unmask, -+}; -+ -+static int aspeed_intc1_irq_domain_translate(struct irq_domain *domain, struct irq_fwspec *fwspec, -+ unsigned long *hwirq, unsigned int *type) -+{ -+ if (fwspec->param_count != 1) -+ return -EINVAL; -+ -+ *hwirq = fwspec->param[0]; -+ *type = IRQ_TYPE_LEVEL_HIGH; -+ return 0; -+} -+ -+static int aspeed_intc1_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) -+{ -+ irq_domain_set_info(domain, irq, hwirq, &aspeed_intc_chip, -+ domain->host_data, handle_level_irq, NULL, NULL); -+ return 0; -+} -+ -+static int aspeed_intc1_irq_domain_activate(struct irq_domain *domain, -+ struct irq_data *data, bool reserve) -+{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); -+ int bank = data->hwirq / INTC1_IRQS_PER_BANK; -+ int bit = data->hwirq % INTC1_IRQS_PER_BANK; -+ u32 mask = BIT(bit); -+ -+ guard(raw_spinlock_irqsave)(&intc_ic->intc_lock); -+ for (int i = 0; i < 3; i++) { -+ void __iomem *sel = intc_ic->base + 0x80 + bank * 4 + 0x20 * i; -+ -+ if (readl(sel) & mask) { -+ writel(readl(sel) & ~mask, sel); -+ if (readl(sel) & mask) -+ return -EACCES; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops aspeed_intc1_ic_irq_domain_ops = { -+ .map = aspeed_intc1_ic_map_irq_domain, -+ .translate = aspeed_intc1_irq_domain_translate, -+ .activate = aspeed_intc1_irq_domain_activate, -+}; -+ -+static int aspeed_intc1_interrupt_ranges(struct aspeed_intc_ic *intc_ic, -+ struct device_node *node, -+ struct device_node *parent_node) -+{ -+ struct of_phandle_args parent_irq; -+ int i, j, n, ret; -+ -+ if (!of_device_is_compatible(parent_node, "aspeed,ast2700-intc0-ic")) -+ return -ENOENT; -+ -+ n = of_property_count_elems_of_size(node, "aspeed,interrupt-ranges", sizeof(u32)); -+ if (n <= 0 || n % 4) -+ return -EINVAL; -+ -+ /* -+ * Each range is described as: -+ * -+ * and we only care about ranges whose phandle matches -+ * this controller's interrupt-parent (&intc0). -+ */ -+ for (i = 0; i < n / 4; i++) { -+ struct device_node *target; -+ phandle parent_handle; -+ u32 base_irq; -+ u32 count; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 4 + 2, &parent_handle); -+ if (ret) -+ return ret; -+ -+ target = of_find_node_by_phandle(parent_handle); -+ if (!target) -+ continue; -+ -+ if (target != parent_node) { -+ of_node_put(target); -+ continue; -+ } -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 4 + 1, &count); -+ if (ret) -+ return ret; -+ -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 4 + 3, &base_irq); -+ if (ret) -+ return ret; -+ -+ for (j = 0; j < count; j++) { -+ int irq; -+ -+ parent_irq.np = parent_node; -+ parent_irq.args_count = 1; -+ parent_irq.args[0] = base_irq + j; -+ irq = irq_create_of_mapping(&parent_irq); -+ if (!irq) -+ continue; -+ -+ irq_set_chained_handler_and_data(irq, -+ aspeed_intc1_ic_irq_handler, -+ intc_ic); -+ } -+ -+ of_node_put(target); -+ } -+ -+ return 0; -+} -+ -+static void aspeed_intc1_disable_int(struct aspeed_intc_ic *intc_ic) -+{ -+ for (int i = 0; i < INTC1_BANK_NUM; i++) -+ writel(0x0, intc_ic->base + INTC1_IER + (0x10 * i)); -+} -+ -+static int aspeed_intc1_ic_of_init(struct device_node *node, struct device_node *parent) -+{ -+ struct aspeed_intc_ic *intc_ic; -+ int ret = 0; -+ -+ if (!parent) { -+ pr_err("missing parent interrupt node\n"); -+ return -ENODEV; -+ } -+ -+ if (!irq_find_host(parent)) -+ return -ENODEV; -+ -+ intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); -+ -+ if (!intc_ic) -+ return -ENOMEM; -+ -+ intc_ic->base = of_iomap(node, 0); -+ if (!intc_ic->base) { -+ pr_err("Failed to iomap intc_ic base\n"); -+ ret = -ENOMEM; -+ goto err_free_ic; -+ } -+ -+ raw_spin_lock_init(&intc_ic->intc_lock); -+ -+ aspeed_intc1_disable_int(intc_ic); -+ intc_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), -+ INTC1_BANK_NUM * INTC1_IRQS_PER_BANK, -+ &aspeed_intc1_ic_irq_domain_ops, intc_ic); -+ if (!intc_ic->irq_domain) { -+ ret = -ENOMEM; -+ goto err_iounmap; -+ } -+ -+ ret = aspeed_intc1_interrupt_ranges(intc_ic, node, parent); -+ if (ret < 0) -+ goto err_iounmap; -+ -+ return 0; -+ -+err_iounmap: -+ iounmap(intc_ic->base); -+err_free_ic: -+ kfree(intc_ic); -+ return ret; -+} -+ -+IRQCHIP_DECLARE(ast2700_intc1_ic, "aspeed,ast2700-intc1-ic", aspeed_intc1_ic_of_init); -diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig -index 992845d7c..e4d2ea2b1 100644 ---- a/drivers/pci/controller/Kconfig -+++ b/drivers/pci/controller/Kconfig -@@ -49,12 +49,19 @@ config PCIE_APPLE - - config PCIE_ASPEED - bool "ASPEED PCIe controller" -- depends on PCI -- depends on OF || COMPILE_TEST -- select PCI_MSI_ARCH_FALLBACKS -+ depends on ARCH_ASPEED || COMPILE_TEST -+ depends on OF -+ depends on PCI_MSI -+ select IRQ_MSI_LIB - help -- Say Y here if you want PCIe controller support on -- ASPEED SoCs. -+ Enable this option to support the PCIe controller found on ASPEED -+ SoCs. -+ -+ This driver provides initialization and management for PCIe -+ Root Complex functionality, including INTx and MSI support. -+ -+ Select Y if your platform uses an ASPEED SoC and requires PCIe -+ connectivity. - - config PCI_VERSATILE - bool "ARM Versatile PB PCI controller" -diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie-aspeed.c -index e569515d3..18e0874e4 100644 ---- a/drivers/pci/controller/pcie-aspeed.c -+++ b/drivers/pci/controller/pcie-aspeed.c -@@ -150,6 +150,7 @@ struct aspeed_pcie_rc_platform { - int reg_intx_sts; - int reg_msi_en; - int reg_msi_sts; -+ int msi_support; - int msi_address; - }; - -@@ -184,14 +185,6 @@ struct aspeed_pcie { - DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS); - }; - --static void aspeed_pcie_intx_ack_irq(struct irq_data *d) --{ -- struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); -- int intx_en = pcie->platform->reg_intx_en; -- -- writel(readl(pcie->reg + intx_en) | BIT(d->hwirq), pcie->reg + intx_en); --} -- - static void aspeed_pcie_intx_mask_irq(struct irq_data *d) - { - struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); -@@ -210,7 +203,6 @@ static void aspeed_pcie_intx_unmask_irq(struct irq_data *d) - - static struct irq_chip aspeed_intx_irq_chip = { - .name = "ASPEED:IntX", -- .irq_ack = aspeed_pcie_intx_ack_irq, - .irq_mask = aspeed_pcie_intx_mask_irq, - .irq_unmask = aspeed_pcie_intx_unmask_irq, - }; -@@ -774,6 +766,9 @@ static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie) - writel(0, pcie->reg + pcie->platform->reg_intx_en); - writel(~0, pcie->reg + pcie->platform->reg_intx_sts); - -+ if (!pcie->platform->msi_support) -+ return 0; -+ - #ifdef CONFIG_PCI_MSI - pcie->dev_domain = - irq_domain_add_linear(NULL, MAX_MSI_HOST_IRQS, &aspeed_msi_domain_ops, pcie); -@@ -1154,6 +1149,7 @@ static struct aspeed_pcie_rc_platform pcie_rc_ast2600 = { - .reg_intx_sts = 0x08, - .reg_msi_en = 0x20, - .reg_msi_sts = 0x28, -+ .msi_support = false, - .msi_address = 0x1e77005c, - }; - -@@ -1163,6 +1159,7 @@ static struct aspeed_pcie_rc_platform pcie_rc_ast2700 = { - .reg_intx_sts = 0x48, - .reg_msi_en = 0x50, - .reg_msi_sts = 0x58, -+ .msi_support = true, - .msi_address = 0x000000f0, - }; - -diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile -index 946e8666c..182de6084 100644 ---- a/drivers/phy/aspeed/Makefile -+++ b/drivers/phy/aspeed/Makefile -@@ -1,4 +1,4 @@ - # SPDX-License-Identifier: GPL-2.0 - --obj-$(CONFIG_PHY_ASPEED_SGMII) += aspeed-sgmii.o -+obj-$(CONFIG_PHY_ASPEED_SGMII) += phy-aspeed-sgmii.o - obj-$(CONFIG_PHY_ASPEED_USB3) += aspeed-usb-phy3.o -\ No newline at end of file -diff --git a/drivers/phy/aspeed/aspeed-sgmii.c b/drivers/phy/aspeed/phy-aspeed-sgmii.c -similarity index 50% -rename from drivers/phy/aspeed/aspeed-sgmii.c -rename to drivers/phy/aspeed/phy-aspeed-sgmii.c -index 677a4044c..11e2c2459 100644 ---- a/drivers/phy/aspeed/aspeed-sgmii.c -+++ b/drivers/phy/aspeed/phy-aspeed-sgmii.c -@@ -10,130 +10,121 @@ - #include - #include - -+#define SCU_HW_REVISION_ID GENMASK(23, 16) -+ - #define SGMII_CFG 0x00 -+#define SGMII_CFG_FIFO_MODE BIT(0) -+#define SGMII_CFG_SPEED_SEL_MASK GENMASK(5, 4) -+#define SGMII_CFG_SPEED_SEL(x) FIELD_PREP(SGMII_CFG_SPEED_SEL_MASK, (x)) -+#define SGMII_CFG_PWR_DOWN BIT(11) -+#define SGMII_CFG_AN_ENABLE BIT(12) -+#define SGMII_CFG_SW_RESET BIT(15) - #define SGMII_LINK_TIMER 0x08 - #define SGMII_NWAY_ACK 0x0c - #define SGMII_PHY_CFG1 0x18 -+#define SGMII_PHY_SPEED_MASK GENMASK(3, 2) -+#define SGMII_PHY_SPEED(x) FIELD_PREP(SGMII_PHY_SPEED_MASK, (x)) - #define SGMII_PHY_PIPE_CTL 0x20 -+#define SGMII_PCTL_TX_NO_DEEMPH BIT(7) - #define SGMII_FIFO_DELAY_THREHOLD 0x28 - #define SGMII_MODE 0x30 -+#define SGMII_MODE_ENABLE BIT(0) -+#define SGMII_MODE_USE_LOCAL_CONFIG BIT(2) - --#define SGMII_CFG_FIFO_MODE BIT(0) --#define SGMII_CFG_SPEED_10M 0 --#define SGMII_CFG_SPEED_100M BIT(4) --#define SGMII_CFG_SPEED_1G BIT(5) --#define SGMII_CFG_PWR_DOWN BIT(11) --#define SGMII_CFG_AN_ENABLE BIT(12) --#define SGMII_CFG_SW_RESET BIT(15) --#define SGMII_PCTL_TX_NO_DEEMPH BIT(7) --#define SGMII_MODE_ENABLE BIT(0) --#define SGMII_MODE_USE_LOCAL_CONFIG BIT(2) -- --#define PLDA_CLK 0x268 -+#define PEHR280 0x280 -+#define SGMII_INTERNAL_CLK_EN BIT(26) -+#define PCIEPHY_CLK 0x268 -+#define PCIEPHY_CLK_FREQ_MULTI_MASK GENMASK(7, 0) -+#define PCIEPHY_CLK_FREQ_MULTI(x) FIELD_PREP(PCIEPHY_CLK_FREQ_MULTI_MASK, (x)) -+#define PCIEPHY_CLK_SEL_INTERNAL_25M BIT(8) - --#define PLDA_CLK_SEL_INTERNAL_25M BIT(8) --#define PLDA_CLK_FREQ_MULTI GENMASK(7, 0) -+#define SGMII_SPEED_10M 0x00 -+#define SGMII_SPEED_100M 0x01 -+#define SGMII_SPEED_1G 0x02 - - struct aspeed_sgmii { - struct device *dev; - void __iomem *regs; -- struct regmap *plda_regmap; -+ struct regmap *pcie_phy_regmap; -+ u8 revision; - }; - --static void aspeed_sgmii_set_nway(struct phy *phy) -+static int aspeed_sgmii_conf(struct phy *phy, bool nway, int speed) - { - struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); -- u32 reg; -- -- /* -- * The PLDA frequency multiplication is X xor 0x19. -- * (X xor 0x19) * clock source = data rate. -- * SGMII data rate is 1.25G, so (0x2b xor 0x19) * 25MHz is equal 1.25G. -- */ -- reg = PLDA_CLK_SEL_INTERNAL_25M | FIELD_PREP(PLDA_CLK_FREQ_MULTI, 0x2b); -- regmap_write(sgmii->plda_regmap, PLDA_CLK, reg); -+ u32 cfg; - - writel(0, sgmii->regs + SGMII_MODE); - - writel(0, sgmii->regs + SGMII_CFG); -- reg = SGMII_CFG_SW_RESET | SGMII_CFG_PWR_DOWN; -- writel(reg, sgmii->regs + SGMII_CFG); -- -- reg = SGMII_CFG_AN_ENABLE; -- writel(reg, sgmii->regs + SGMII_CFG); -- -- writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); -+ writel(SGMII_CFG_SW_RESET | SGMII_CFG_PWR_DOWN, sgmii->regs + SGMII_CFG); -+ if (nway) { -+ if (sgmii->revision == 1) -+ writel(SGMII_CFG_AN_ENABLE, sgmii->regs + SGMII_CFG); -+ else -+ writel(SGMII_CFG_AN_ENABLE | SGMII_CFG_FIFO_MODE, -+ sgmii->regs + SGMII_CFG); -+ } else { -+ switch (speed) { -+ case SPEED_10: -+ cfg = SGMII_SPEED_10M; -+ break; -+ case SPEED_100: -+ cfg = SGMII_SPEED_100M; -+ break; -+ case SPEED_1000: -+ cfg = SGMII_SPEED_1G; -+ break; -+ default: -+ return -EINVAL; -+ } -+ writel(SGMII_PHY_SPEED(cfg), sgmii->regs + SGMII_PHY_CFG1); -+ if (sgmii->revision == 1) -+ writel(SGMII_CFG_SPEED_SEL(cfg), -+ sgmii->regs + SGMII_CFG); -+ else -+ writel(SGMII_CFG_SPEED_SEL(cfg) | SGMII_CFG_FIFO_MODE, -+ sgmii->regs + SGMII_CFG); -+ } - -+ if (sgmii->revision == 1) -+ writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); -+ else -+ writel(0x0e, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); - writel(SGMII_PCTL_TX_NO_DEEMPH, sgmii->regs + SGMII_PHY_PIPE_CTL); - -- /* Set link timer for Nway state change */ -+ /* Set link timer for state change */ - writel(0x100, sgmii->regs + SGMII_LINK_TIMER); - - /* Bit 0 always sets to 1 in ACK message */ - writel(0x1, sgmii->regs + SGMII_NWAY_ACK); - -- reg = SGMII_MODE_ENABLE; -- writel(reg, sgmii->regs + SGMII_MODE); -+ cfg = SGMII_MODE_ENABLE; -+ if (!nway) -+ cfg |= SGMII_MODE_USE_LOCAL_CONFIG; -+ writel(cfg, sgmii->regs + SGMII_MODE); -+ -+ return 0; - } - - static int aspeed_sgmii_phy_init(struct phy *phy) - { -- aspeed_sgmii_set_nway(phy); -- -- return 0; -+ /* Default to enable Nway, not need configure speed */ -+ return aspeed_sgmii_conf(phy, true, 0); - } - --static int aspeed_sgmii_phy_exit(struct phy *phy) -+static int aspeed_sgmii_phy_set_speed(struct phy *phy, int speed) - { -- struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); -- -- /* Disable SGMII controller */ -- writel(0, sgmii->regs + SGMII_MODE); -- -- return 0; -+ return aspeed_sgmii_conf(phy, false, speed); - } - --static int aspeed_sgmii_phy_set_speed(struct phy *phy, int speed) -+static int aspeed_sgmii_phy_exit(struct phy *phy) - { - struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); -- u32 reg; -- -- reg = PLDA_CLK_SEL_INTERNAL_25M | FIELD_PREP(PLDA_CLK_FREQ_MULTI, 0x2b); -- regmap_write(sgmii->plda_regmap, PLDA_CLK, reg); -- -- switch (speed) { -- case SPEED_10: -- reg = SGMII_CFG_SPEED_10M; -- break; -- case SPEED_100: -- reg = SGMII_CFG_SPEED_100M; -- break; -- case SPEED_1000: -- reg = SGMII_CFG_SPEED_1G; -- break; -- default: -- return -EINVAL; -- } - -+ /* Disable SGMII controller */ - writel(0, sgmii->regs + SGMII_MODE); - -- writel((reg >> 2), sgmii->regs + SGMII_PHY_CFG1); -- -- writel(0, sgmii->regs + SGMII_CFG); -- writel(SGMII_CFG_SW_RESET | SGMII_CFG_PWR_DOWN, sgmii->regs + SGMII_CFG); -- writel(reg, sgmii->regs + SGMII_CFG); -- -- writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); -- writel(SGMII_PCTL_TX_NO_DEEMPH, sgmii->regs + SGMII_PHY_PIPE_CTL); -- -- /* Set link timer for Nway state change */ -- writel(0x100, sgmii->regs + SGMII_LINK_TIMER); -- -- /* Bit 0 always sets to 1 in ACK message */ -- writel(0x1, sgmii->regs + SGMII_NWAY_ACK); -- -- writel(SGMII_MODE_ENABLE | SGMII_MODE_USE_LOCAL_CONFIG, sgmii->regs + SGMII_MODE); -- - return 0; - } - -@@ -146,12 +137,14 @@ static const struct phy_ops aspeed_sgmii_phyops = { - - static int aspeed_sgmii_probe(struct platform_device *pdev) - { -+ struct phy_provider *provider; - struct aspeed_sgmii *sgmii; -+ struct regmap *scu_regmap; -+ struct device_node *np; - struct resource *res; - struct device *dev; -- struct device_node *np; -- struct phy_provider *provider; - struct phy *phy; -+ u32 reg; - - dev = &pdev->dev; - -@@ -174,13 +167,23 @@ static int aspeed_sgmii_probe(struct platform_device *pdev) - } - - np = pdev->dev.of_node; -- sgmii->plda_regmap = syscon_regmap_lookup_by_phandle(np, "aspeed,plda"); -- if (IS_ERR(sgmii->plda_regmap)) { -- dev_err(sgmii->dev, "Unable to find plda regmap (%ld)\n", -- PTR_ERR(sgmii->plda_regmap)); -- return PTR_ERR(sgmii->plda_regmap); -+ sgmii->pcie_phy_regmap = syscon_regmap_lookup_by_phandle(np, "phys"); -+ if (IS_ERR(sgmii->pcie_phy_regmap)) { -+ dev_err(sgmii->dev, "Unable to find phys regmap (%ld)\n", -+ PTR_ERR(sgmii->pcie_phy_regmap)); -+ return PTR_ERR(sgmii->pcie_phy_regmap); - } - -+ scu_regmap = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); -+ if (IS_ERR(scu_regmap)) { -+ dev_err(sgmii->dev, "Unable to find SCU regmap (%ld)\n", -+ PTR_ERR(scu_regmap)); -+ return PTR_ERR(scu_regmap); -+ } -+ -+ regmap_read(scu_regmap, 0x00, ®); -+ sgmii->revision = FIELD_GET(SCU_HW_REVISION_ID, reg); -+ - phy = devm_phy_create(dev, NULL, &aspeed_sgmii_phyops); - if (IS_ERR(phy)) { - dev_err(&pdev->dev, "failed to create PHY\n"); -@@ -193,6 +196,19 @@ static int aspeed_sgmii_probe(struct platform_device *pdev) - - phy_set_drvdata(phy, sgmii); - -+ /* -+ * The PLDA frequency multiplication is X xor 0x19. -+ * (X xor 0x19) * clock source = data rate. -+ * SGMII data rate is 1.25G, so (0x2b xor 0x19) * 25MHz is equal 1.25G. -+ */ -+ reg = PCIEPHY_CLK_SEL_INTERNAL_25M | PCIEPHY_CLK_FREQ_MULTI(0x2b); -+ regmap_write(sgmii->pcie_phy_regmap, PCIEPHY_CLK, reg); -+ if (sgmii->revision > 1) { -+ regmap_read(sgmii->pcie_phy_regmap, PEHR280, ®); -+ reg |= SGMII_INTERNAL_CLK_EN; -+ regmap_write(sgmii->pcie_phy_regmap, PEHR280, reg); -+ } -+ - dev_info(dev, "module loaded\n"); - - return 0; -@@ -214,5 +230,5 @@ static struct platform_driver aspeed_sgmii_driver = { - module_platform_driver(aspeed_sgmii_driver); - - MODULE_AUTHOR("Jacky Chou "); --MODULE_DESCRIPTION("Control of ASPEED SGMII Device"); -+MODULE_DESCRIPTION("ASPEED SGMII Serdes/PHY controller"); - MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig -index 60f356bbb..8f87f7fb9 100644 ---- a/drivers/soc/aspeed/Kconfig -+++ b/drivers/soc/aspeed/Kconfig -@@ -144,41 +144,6 @@ config ASPEED_UDMA - config ASPEED_PCIE_MMBI - tristate "ASPEED PCIE MMBI" - --config ASPEED_ESPI -- tristate "ASPEED eSPI slave driver" -- select AST2500_ESPI if MACH_ASPEED_G5 -- select AST2600_ESPI if MACH_ASPEED_G6 -- default n -- --config AST2500_ESPI -- tristate -- depends on ASPEED_ESPI -- help -- Enable driver support for Aspeed AST2500 eSPI engine. -- --config AST2600_ESPI -- tristate "ASPEED AST2600 eSPI slave driver" -- help -- Enable driver support for Aspeed AST2600 eSPI engine. The eSPI engine -- plays as a slave device in BMC to communicate with the Host over -- the eSPI interface. The four eSPI channels, namely peripheral, -- virtual wire, out-of-band, and flash are supported. -- --config AST2700_ESPI -- tristate "ASPEED AST2700 eSPI slave driver" -- help -- Enable driver support for Aspeed AST2700 eSPI engine. The eSPI engine -- plays as a slave device in BMC to communicate with the Host over -- the eSPI interface. The four eSPI channels, namely peripheral, -- virtual wire, out-of-band, and flash are supported. -- --config AST2700_RTC_OVER_ESPI -- tristate "ASPEED AST2700 RTC over eSPI drvier" -- depends on HAS_IOMEM -- help -- Enable driver support for Aspeed AST2700 RTC over eSPI function. -- Periodically copies RAM content from a RTC tm to a memory-mapped eSPI region. -- - config ASPEED_OTP - tristate - help -@@ -201,6 +166,7 @@ config AST2700_OTP - help - Enable driver support for Aspeed AST2700 OTP driver. - -+source "drivers/soc/aspeed/espi/Kconfig" - source "drivers/soc/aspeed/rvas/Kconfig" - - endmenu -diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile -index a6c21bd61..0de14f6fc 100644 ---- a/drivers/soc/aspeed/Makefile -+++ b/drivers/soc/aspeed/Makefile -@@ -11,9 +11,6 @@ obj-$(CONFIG_ASPEED_SSP) += aspeed-ssp.o - obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o - obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o - obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o --obj-$(CONFIG_AST2500_ESPI) += ast2500-espi.o --obj-$(CONFIG_AST2600_ESPI) += ast2600-espi.o --obj-$(CONFIG_AST2700_ESPI) += ast2700-espi.o - obj-$(CONFIG_ASPEED_RVAS) += rvas/ - obj-$(CONFIG_ARCH_ASPEED) += aspeed-usb-phy.o - obj-$(CONFIG_ARCH_ASPEED) += aspeed-usb-hp.o -@@ -21,6 +18,6 @@ obj-$(CONFIG_ASPEED_MCTP) += aspeed-mctp.o - obj-$(CONFIG_ASPEED_DISP_INTF) += aspeed-disp-intf.o - obj-$(CONFIG_ASPEED_PCIE_MMBI) += aspeed-pcie-mmbi.o - obj-$(CONFIG_ASPEED_MBOX) += aspeed-mbox.o --obj-$(CONFIG_AST2700_RTC_OVER_ESPI) += ast2700-rtc-over-espi.o - obj-$(CONFIG_AST2600_OTP) += ast2600-otp.o - obj-$(CONFIG_AST2700_OTP) += ast2700-otp.o -+obj-y += espi/ -diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc-dev.c -index 997cc7a9e..d3bc5a36f 100644 ---- a/drivers/soc/aspeed/aspeed-bmc-dev.c -+++ b/drivers/soc/aspeed/aspeed-bmc-dev.c -@@ -120,6 +120,7 @@ struct aspeed_bmc_device { - void __iomem *reg_base; - dma_addr_t bmc_mem_phy; - phys_addr_t bmc_mem_size; -+ void *bmc_mem_cpu; - - int pcie2lpc; - int irq; -@@ -146,18 +147,15 @@ static int aspeed_bmc_device_mmap(struct file *file, struct vm_area_struct *vma) - { - struct aspeed_bmc_device *bmc_device = file_aspeed_bmc_device(file); - unsigned long vsize = vma->vm_end - vma->vm_start; -- pgprot_t prot = vma->vm_page_prot; - -- if (((vma->vm_pgoff << PAGE_SHIFT) + vsize) > bmc_device->bmc_mem_size) -+ if (vsize > bmc_device->bmc_mem_size) - return -EINVAL; - -- prot = pgprot_noncached(prot); -+ return dma_mmap_coherent(bmc_device->dev, vma, -+ bmc_device->bmc_mem_cpu, -+ bmc_device->bmc_mem_phy, -+ bmc_device->bmc_mem_size); - -- if (remap_pfn_range(vma, vma->vm_start, -- (bmc_device->bmc_mem_phy >> PAGE_SHIFT) + vma->vm_pgoff, vsize, prot)) -- return -EAGAIN; -- -- return 0; - } - - static const struct file_operations aspeed_bmc_device_fops = { -@@ -581,42 +579,53 @@ static int aspeed_bmc_device_probe(struct platform_device *pdev) - bmc_device->dev = dev; - bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(bmc_device->reg_base)) -- goto out_region; -+ return PTR_ERR(bmc_device->reg_base); -+ -+ ret = of_reserved_mem_device_init(dev); -+ if (ret) { -+ dev_err(dev, "of_reserved_mem_device_init failed: %d\n", ret); -+ return ret; -+ } - - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); - if (ret) { - dev_err(dev, "cannot set 64-bits DMA mask\n"); -- goto out_region; -+ return ret; - } - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np || of_address_to_resource(np, 0, &res)) { - dev_err(dev, "Failed to find memory-region.\n"); -- ret = -ENOMEM; -- goto out_region; -+ return -ENOMEM; - } - - of_node_put(np); - -- bmc_device->bmc_mem_phy = res.start; - bmc_device->bmc_mem_size = resource_size(&res); -+ bmc_device->bmc_mem_cpu = dmam_alloc_coherent(dev, bmc_device->bmc_mem_size, -+ &bmc_device->bmc_mem_phy, GFP_KERNEL); -+ if (!bmc_device->bmc_mem_cpu) { -+ dev_err(dev, "Failed to allocate BMC memory.\n"); -+ return -ENOMEM; -+ } - - bmc_device->irq = platform_get_irq(pdev, 0); - if (bmc_device->irq < 0) { - dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", bmc_device->irq); -- goto out_unmap; -+ return bmc_device->irq; - } -+ - ret = devm_request_irq(&pdev->dev, bmc_device->irq, aspeed_bmc_dev_isr, 0, - dev_name(&pdev->dev), bmc_device); - if (ret) { - dev_err(dev, "aspeed bmc device Unable to get IRQ"); -- goto out_unmap; -+ return ret; - } - - ret = aspeed_bmc_device_setup_queue(pdev); - if (ret) { - dev_err(dev, "Cannot setup queue message"); -- goto out_irq; -+ goto out; - } - - ret = aspeed_bmc_device_setup_memory_mapping(pdev); -@@ -657,12 +666,7 @@ static int aspeed_bmc_device_probe(struct platform_device *pdev) - out_free_queue: - for (i = 0; i < ASPEED_QUEUE_NUM; i++) - sysfs_remove_bin_file(&pdev->dev.kobj, &bmc_device->queue[i].bin); --out_irq: -- devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device); --out_unmap: -- iounmap(bmc_device->reg_base); --out_region: -- devm_kfree(&pdev->dev, bmc_device); -+out: - dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret); - return ret; - } -diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc-pcc.c -index 158d38a03..c0aa07e16 100644 ---- a/drivers/soc/aspeed/aspeed-lpc-pcc.c -+++ b/drivers/soc/aspeed/aspeed-lpc-pcc.c -@@ -73,6 +73,9 @@ static DEFINE_IDA(aspeed_pcc_ida); - - #define PCC_DMA_BUFSZ (256 * SZ_1K) - -+/* Except for the 1-byte threshold, the rest represent fractions of the FIFO. -+ * Ex. PCC_FIFO_THR_1_EIGHTH means 1/8th of the FIFO size. -+ */ - enum pcc_fifo_threshold { - PCC_FIFO_THR_1_BYTE, - PCC_FIFO_THR_1_EIGHTH, -@@ -82,7 +85,6 @@ enum pcc_fifo_threshold { - PCC_FIFO_THR_5_EIGHTH, - PCC_FIFO_THR_6_EIGHTH, - PCC_FIFO_THR_7_EIGHTH, -- PCC_FIFO_THR_8_EIGHTH, - }; - - enum pcc_record_mode { -@@ -116,6 +118,7 @@ struct aspeed_pcc_ctrl { - wait_queue_head_t wq; - struct miscdevice mdev; - int mdev_id; -+ spinlock_t lock; /* protects access to the FIFO and DMA pointer */ - }; - - static inline bool is_valid_rec_mode(uint32_t mode) -@@ -176,22 +179,26 @@ static irqreturn_t aspeed_pcc_dma_isr(int irq, void *arg) - struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; - struct kfifo *fifo = &pcc->fifo; - -+ spin_lock(&pcc->lock); - regmap_write_bits(pcc->regmap, PCCR2, PCCR2_INT_STATUS_DMA_DONE, PCCR2_INT_STATUS_DMA_DONE); - - regmap_read(pcc->regmap, PCCR6, ®); - wptr = (reg & PCCR6_DMA_CUR_ADDR) - (pcc->dma.addr & PCCR6_DMA_CUR_ADDR); - rptr = pcc->dma.rptr; - -- do { -- if (kfifo_is_full(fifo)) -- kfifo_skip(fifo); -- -- kfifo_put(fifo, pcc->dma.virt[rptr]); -- -- rptr = (rptr + 1) % pcc->dma.size; -- } while (rptr != wptr); -+ /* If kfifo is empty or has enough space, insert new data; -+ * otherwise, discard the new data. -+ */ -+ if (rptr <= wptr) { -+ kfifo_in(fifo, pcc->dma.virt + rptr, wptr - rptr); -+ } else { -+ /* Handle wrap-around case */ -+ kfifo_in(fifo, pcc->dma.virt + rptr, pcc->dma.size - rptr); -+ kfifo_in(fifo, pcc->dma.virt, wptr); -+ } - -- pcc->dma.rptr = rptr; -+ pcc->dma.rptr = wptr; -+ spin_unlock(&pcc->lock); - - wake_up_interruptible(&pcc->wq); - -@@ -284,6 +291,10 @@ static int aspeed_pcc_enable(struct aspeed_pcc_ctrl *pcc, struct device *dev) - PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE, - PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE); - -+ regmap_update_bits(pcc->regmap, PCCR0, -+ PCCR0_RX_TRIG_LVL_MASK, -+ PCC_FIFO_THR_2_EIGHTH << PCCR0_RX_TRIG_LVL_SHIFT); -+ - regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN, PCCR0_EN); - - return 0; -@@ -347,6 +358,8 @@ static int aspeed_pcc_probe(struct platform_device *pdev) - if (rc) - return rc; - -+ spin_lock_init(&pcc->lock); -+ - /* Disable PCC to clean up DMA buffer before request IRQ. */ - rc = aspeed_pcc_disable(pcc); - if (rc) { -diff --git a/drivers/soc/aspeed/aspeed-mbox.c b/drivers/soc/aspeed/aspeed-mbox.c -index 7a656f338..f8e006a11 100644 ---- a/drivers/soc/aspeed/aspeed-mbox.c -+++ b/drivers/soc/aspeed/aspeed-mbox.c -@@ -295,7 +295,7 @@ static const struct of_device_id mbox_cl_match[] = { - { .compatible = "aspeed,aspeed-mbox" }, - {}, - }; --MODULE_DEVICE_TABLE(of, mbox_test_match); -+MODULE_DEVICE_TABLE(of, mbox_cl_match); - - static struct platform_driver aspeed_mbox_driver = { - .driver = { -diff --git a/drivers/soc/aspeed/aspeed-mctp.c b/drivers/soc/aspeed/aspeed-mctp.c -index efeb424d2..b549013b7 100644 ---- a/drivers/soc/aspeed/aspeed-mctp.c -+++ b/drivers/soc/aspeed/aspeed-mctp.c -@@ -2291,6 +2291,12 @@ static int aspeed_mctp_dma_init(struct aspeed_mctp *priv) - BUILD_BUG_ON(TX_PACKET_COUNT >= TX_MAX_PACKET_COUNT); - BUILD_BUG_ON(RX_PACKET_COUNT >= RX_MAX_PACKET_COUNT); - -+ ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); -+ if (ret) { -+ dev_err(priv->dev, "cannot set 64-bits DMA mask\n"); -+ return ret; -+ } -+ - ret = of_reserved_mem_device_init(priv->dev); - if (ret) { - dev_err(priv->dev, "device does not have specific DMA pool: %d\n", -@@ -2303,12 +2309,6 @@ static int aspeed_mctp_dma_init(struct aspeed_mctp *priv) - if (ret) - return ret; - -- ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); -- if (ret) { -- dev_err(priv->dev, "cannot set 64-bits DMA mask\n"); -- return ret; -- } -- - alloc_size = PAGE_ALIGN(priv->rx_packet_count * priv->match_data->packet_unit_size); - rx->data.vaddr = - dma_alloc_coherent(priv->dev, alloc_size, &rx->data.dma_handle, GFP_KERNEL); -@@ -2400,8 +2400,8 @@ static int aspeed_mctp_irq_init(struct aspeed_mctp *priv) - aspeed_mctp_irq_enable(priv); - } - irq = platform_get_irq_byname(pdev, "pcie"); -- if (!irq) -- return -ENODEV; -+ if (irq < 0) -+ return irq; - - ret = devm_request_irq(priv->dev, irq, aspeed_mctp_pcie_rst_irq_handler, - IRQF_SHARED, dev_name(&pdev->dev), priv); -diff --git a/drivers/soc/aspeed/aspeed-pcie-mmbi.c b/drivers/soc/aspeed/aspeed-pcie-mmbi.c -index 654e7fe72..9c994dde5 100644 ---- a/drivers/soc/aspeed/aspeed-pcie-mmbi.c -+++ b/drivers/soc/aspeed/aspeed-pcie-mmbi.c -@@ -884,6 +884,7 @@ static int aspeed_pcie_mmbi_probe(struct platform_device *pdev) - mmbi->irq = platform_get_irq(pdev, 0); - if (mmbi->irq < 0) { - dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", mmbi->irq); -+ ret = mmbi->irq; - goto out_unmap; - } - ret = devm_request_irq(&pdev->dev, mmbi->irq, aspeed_pcie_mmbi_isr, 0, dev_name(&pdev->dev), -@@ -931,7 +932,7 @@ static int aspeed_pcie_mmbi_probe(struct platform_device *pdev) - iounmap(mmbi->mem_virt); - out_region: - devm_kfree(dev, mmbi); -- dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret); -+ dev_warn(dev, "aspeed pcie mmbi: driver init failed (ret=%d)!\n", ret); - return ret; - } - -diff --git a/drivers/soc/aspeed/aspeed-udma.c b/drivers/soc/aspeed/aspeed-udma.c -index e013016a0..8dc6f3cfc 100644 ---- a/drivers/soc/aspeed/aspeed-udma.c -+++ b/drivers/soc/aspeed/aspeed-udma.c -@@ -4,7 +4,6 @@ - */ - #include - #include --#include - #include - #include - #include -@@ -61,8 +60,7 @@ enum aspeed_udma_bufsz_code { - struct aspeed_udma_chan { - dma_addr_t dma_addr; - -- struct kfifo *fifo; -- u32 fifo_sz; -+ u32 rb_sz; - - aspeed_udma_cb_t cb; - void *cb_arg; -@@ -161,12 +159,12 @@ int aspeed_udma_free_rx_chan(u32 ch_no) - } - EXPORT_SYMBOL(aspeed_udma_free_rx_chan); - --static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, -- struct kfifo *fifo, u32 fifo_sz, -- aspeed_udma_cb_t cb, void *id, bool dis_tmout, bool is_tx) -+static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, -+ aspeed_udma_cb_t cb, void *id, -+ bool dis_tmout, bool is_tx) - { - int retval = 0; -- int fifosz_code; -+ int rbsz_code; - - u32 reg; - unsigned long flags; -@@ -177,13 +175,8 @@ static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, - goto out; - } - -- if (IS_ERR_OR_NULL(fifo) || IS_ERR_OR_NULL(fifo->kfifo.data)) { -- retval = -EINVAL; -- goto out; -- } -- -- fifosz_code = aspeed_udma_get_bufsz_code(fifo_sz); -- if (fifosz_code < 0) { -+ rbsz_code = aspeed_udma_get_bufsz_code(rb_sz); -+ if (rbsz_code < 0) { - retval = -EINVAL; - goto out; - } -@@ -202,7 +195,7 @@ static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, - - reg = FIELD_PREP(UDMA_TX_CTRL_BUF_ADDRH, (u64)addr >> 32) | - ((dis_tmout) ? UDMA_TX_CTRL_TMOUT_DIS : 0) | -- FIELD_PREP(UDMA_TX_CTRL_BUFSZ, fifosz_code); -+ FIELD_PREP(UDMA_TX_CTRL_BUFSZ, rbsz_code); - writel(reg, udma->regs + UDMA_CHX_TX_CTRL(ch_no)); - - writel(addr, udma->regs + UDMA_CHX_TX_BUF_ADDR(ch_no)); -@@ -218,15 +211,14 @@ static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, - - reg = FIELD_PREP(UDMA_RX_CTRL_BUF_ADDRH, (u64)addr >> 32) | - ((dis_tmout) ? UDMA_RX_CTRL_TMOUT_DIS : 0) | -- FIELD_PREP(UDMA_RX_CTRL_BUFSZ, fifosz_code); -+ FIELD_PREP(UDMA_RX_CTRL_BUFSZ, rbsz_code); - writel(reg, udma->regs + UDMA_CHX_RX_CTRL(ch_no)); - - writel(addr, udma->regs + UDMA_CHX_RX_BUF_ADDR(ch_no)); - } - - ch = (is_tx) ? &udma->tx_chs[ch_no] : &udma->rx_chs[ch_no]; -- ch->fifo = fifo; -- ch->fifo_sz = fifo_sz; -+ ch->rb_sz = rb_sz; - ch->cb = cb; - ch->cb_arg = id; - ch->dma_addr = addr; -@@ -238,20 +230,18 @@ static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, - return 0; - } - --int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, -- struct kfifo *fifo, u32 fifo_sz, -+int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, - aspeed_udma_cb_t cb, void *id, bool dis_tmout) - { -- return aspeed_udma_request_chan(ch_no, addr, fifo, fifo_sz, cb, id, -+ return aspeed_udma_request_chan(ch_no, addr, rb_sz, cb, id, - dis_tmout, true); - } - EXPORT_SYMBOL(aspeed_udma_request_tx_chan); - --int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, -- struct kfifo *fifo, u32 fifo_sz, -+int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, - aspeed_udma_cb_t cb, void *id, bool dis_tmout) - { -- return aspeed_udma_request_chan(ch_no, addr, fifo, fifo_sz, cb, id, -+ return aspeed_udma_request_chan(ch_no, addr, rb_sz, cb, id, - dis_tmout, false); - } - EXPORT_SYMBOL(aspeed_udma_request_rx_chan); -diff --git a/drivers/soc/aspeed/espi/Kconfig b/drivers/soc/aspeed/espi/Kconfig -new file mode 100644 -index 000000000..f0ccc7518 ---- /dev/null -+++ b/drivers/soc/aspeed/espi/Kconfig -@@ -0,0 +1,18 @@ -+menu "ASPEED eSPI drivers" -+ -+config ASPEED_ESPI -+ tristate "ASPEED eSPI slave driver" -+ help -+ Enable driver support for Aspeed AST2700 eSPI engine. The eSPI engine -+ plays as a slave device in BMC to communicate with the Host over -+ the eSPI interface. The four eSPI channels, namely peripheral, -+ virtual wire, out-of-band, and flash are supported. -+ -+config AST2700_RTC_OVER_ESPI -+ tristate "ASPEED AST2700 RTC over eSPI drvier" -+ depends on HAS_IOMEM -+ help -+ Enable driver support for Aspeed AST2700 RTC over eSPI function. -+ Periodically copies RAM content from a RTC tm to a memory-mapped eSPI region. -+ -+endmenu -diff --git a/drivers/soc/aspeed/espi/Makefile b/drivers/soc/aspeed/espi/Makefile -new file mode 100644 -index 000000000..559d5dd97 ---- /dev/null -+++ b/drivers/soc/aspeed/espi/Makefile -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_ASPEED_ESPI) += \ -+ ast2700-espi.o \ -+ ast2600-espi.o \ -+ ast2500-espi.o \ -+ aspeed-espi.o -+obj-$(CONFIG_AST2700_RTC_OVER_ESPI) += ast2700-rtc-over-espi.o -diff --git a/drivers/soc/aspeed/aspeed-espi-comm.h b/drivers/soc/aspeed/espi/aspeed-espi-comm.h -similarity index 83% -rename from drivers/soc/aspeed/aspeed-espi-comm.h -rename to drivers/soc/aspeed/espi/aspeed-espi-comm.h -index 29468437a..e810d732b 100644 ---- a/drivers/soc/aspeed/aspeed-espi-comm.h -+++ b/drivers/soc/aspeed/espi/aspeed-espi-comm.h -@@ -1,5 +1,6 @@ - /* SPDX-License-Identifier: GPL-2.0+ */ - /* -+ * Aspeed eSPI protocol definitions and IOCTL methods - * Copyright 2023 Aspeed Technology Inc. - */ - #ifndef __ASPEED_ESPI_COMM_H__ -@@ -44,71 +45,71 @@ - * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. - */ - struct espi_comm_hdr { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; - }; - - struct espi_perif_mem32 { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint32_t addr_be; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u32 addr_be; -+ u8 data[]; - } __packed; - - struct espi_perif_mem64 { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint32_t addr_be; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u32 addr_be; -+ u8 data[]; - } __packed; - - struct espi_perif_msg { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint8_t msg_code; -- uint8_t msg_byte[4]; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u8 msg_code; -+ u8 msg_byte[4]; -+ u8 data[]; - } __packed; - - struct espi_perif_cmplt { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u8 data[]; - } __packed; - - struct espi_oob_msg { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u8 data[]; - }; - - struct espi_flash_rwe { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint32_t addr_be; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u32 addr_be; -+ u8 data[]; - } __packed; - - struct espi_flash_cmplt { -- uint8_t cyc; -- uint8_t len_h : 4; -- uint8_t tag : 4; -- uint8_t len_l; -- uint8_t data[]; -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u8 data[]; - } __packed; - - #define ESPI_MAX_PLD_LEN BIT(12) -@@ -140,8 +141,8 @@ struct espi_flash_cmplt { - #define ESPI_MAX_PKT_LEN (sizeof(struct espi_perif_msg) + ESPI_MAX_PLD_LEN) - - struct aspeed_espi_ioc { -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - }; - - /* -@@ -171,14 +172,14 @@ struct aspeed_espi_ioc { - * Write the output value1 of GPIO over the VW channel - */ - #define ASPEED_ESPI_VW_GET_GPIO_VAL _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -- 0x10, uint32_t) -+ 0x10, u32) - #define ASPEED_ESPI_VW_PUT_GPIO_VAL _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -- 0x11, uint32_t) -+ 0x11, u32) - #ifdef CONFIG_ARM64 - #define ASPEED_ESPI_VW_GET_GPIO_VAL1 _IOR(__ASPEED_ESPI_IOCTL_MAGIC, \ -- 0x12, uint32_t) -+ 0x12, u32) - #define ASPEED_ESPI_VW_PUT_GPIO_VAL1 _IOW(__ASPEED_ESPI_IOCTL_MAGIC, \ -- 0x13, uint32_t) -+ 0x13, u32) - #endif - /* - * Out-of-band Channel (CH2) -diff --git a/drivers/soc/aspeed/espi/aspeed-espi.c b/drivers/soc/aspeed/espi/aspeed-espi.c -new file mode 100644 -index 000000000..26459ea0b ---- /dev/null -+++ b/drivers/soc/aspeed/espi/aspeed-espi.c -@@ -0,0 +1,256 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Unified Aspeed eSPI driver (AST2500/AST2600/AST2700) -+ * -+ * This wraps the existing SoC-specific implementations behind a -+ * single driver name and compatible strings. For now we keep the -+ * full implementations in their original files and dispatch through -+ * small per-SoC glue ops. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "aspeed-espi.h" -+#include "ast2500-espi.h" -+#include "ast2600-espi.h" -+#include "ast2700-espi.h" -+ -+struct aspeed_espi_ops { -+ enum aspeed_espi_platform_id platform_id; -+ void (*espi_pre_init)(struct aspeed_espi *espi); -+ void (*espi_post_init)(struct aspeed_espi *espi); -+ void (*espi_deinit)(struct aspeed_espi *espi); -+ int (*espi_perif_probe)(struct aspeed_espi *espi); -+ int (*espi_perif_remove)(struct aspeed_espi *espi); -+ int (*espi_vw_probe)(struct aspeed_espi *espi); -+ int (*espi_vw_remove)(struct aspeed_espi *espi); -+ int (*espi_oob_probe)(struct aspeed_espi *espi); -+ int (*espi_oob_remove)(struct aspeed_espi *espi); -+ int (*espi_flash_probe)(struct aspeed_espi *espi); -+ int (*espi_flash_remove)(struct aspeed_espi *espi); -+ irqreturn_t (*espi_isr)(int irq, void *espi); -+}; -+ -+static const struct aspeed_espi_ops aspeed_espi_ast2500_ops = { -+ .platform_id = ASPEED_ESPI_PLATFORM_ID_AST2500, -+ .espi_pre_init = ast2500_espi_pre_init, -+ .espi_post_init = ast2500_espi_post_init, -+ .espi_deinit = ast2500_espi_deinit, -+ .espi_perif_probe = ast2500_espi_perif_probe, -+ .espi_perif_remove = ast2500_espi_perif_remove, -+ .espi_vw_probe = ast2500_espi_vw_probe, -+ .espi_vw_remove = ast2500_espi_vw_remove, -+ .espi_oob_probe = ast2500_espi_oob_probe, -+ .espi_oob_remove = ast2500_espi_oob_remove, -+ .espi_flash_probe = ast2500_espi_flash_probe, -+ .espi_flash_remove = ast2500_espi_flash_remove, -+ .espi_isr = ast2500_espi_isr, -+}; -+ -+static const struct aspeed_espi_ops aspeed_espi_ast2600_ops = { -+ .platform_id = ASPEED_ESPI_PLATFORM_ID_AST2600, -+ .espi_pre_init = ast2600_espi_pre_init, -+ .espi_post_init = ast2600_espi_post_init, -+ .espi_deinit = ast2600_espi_deinit, -+ .espi_perif_probe = ast2600_espi_perif_probe, -+ .espi_perif_remove = ast2600_espi_perif_remove, -+ .espi_vw_probe = ast2600_espi_vw_probe, -+ .espi_vw_remove = ast2600_espi_vw_remove, -+ .espi_oob_probe = ast2600_espi_oob_probe, -+ .espi_oob_remove = ast2600_espi_oob_remove, -+ .espi_flash_probe = ast2600_espi_flash_probe, -+ .espi_flash_remove = ast2600_espi_flash_remove, -+ .espi_isr = ast2600_espi_isr, -+}; -+ -+static const struct aspeed_espi_ops aspeed_espi_ast2700_ops = { -+ .platform_id = ASPEED_ESPI_PLATFORM_ID_AST2700, -+ .espi_pre_init = ast2700_espi_pre_init, -+ .espi_post_init = ast2700_espi_post_init, -+ .espi_deinit = ast2700_espi_deinit, -+ .espi_perif_probe = ast2700_espi_perif_probe, -+ .espi_perif_remove = ast2700_espi_perif_remove, -+ .espi_vw_probe = ast2700_espi_vw_probe, -+ .espi_vw_remove = ast2700_espi_vw_remove, -+ .espi_oob_probe = ast2700_espi_oob_probe, -+ .espi_oob_remove = ast2700_espi_oob_remove, -+ .espi_flash_probe = ast2700_espi_flash_probe, -+ .espi_flash_remove = ast2700_espi_flash_remove, -+ .espi_isr = ast2700_espi_isr, -+}; -+ -+static const struct of_device_id aspeed_espi_of_matches[] = { -+ { .compatible = "aspeed,ast2500-espi", .data = &aspeed_espi_ast2500_ops }, -+ { .compatible = "aspeed,ast2600-espi", .data = &aspeed_espi_ast2600_ops }, -+ { .compatible = "aspeed,ast2700-espi", .data = &aspeed_espi_ast2700_ops }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_espi_of_matches); -+ -+static int aspeed_espi_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *match; -+ struct device *dev = &pdev->dev; -+ struct aspeed_espi *espi; -+ struct resource *res; -+ int rc; -+ -+ espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -+ if (!espi) -+ return -ENOMEM; -+ -+ espi->dev = dev; -+ match = of_match_device(aspeed_espi_of_matches, dev); -+ if (!match) -+ return -ENODEV; -+ espi->ops = match->data; -+ -+ espi->pdev = pdev; -+ -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(dev, "cannot get resource\n"); -+ return -ENODEV; -+ } -+ -+ espi->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(espi->regs)) { -+ dev_err(dev, "cannot map registers\n"); -+ return PTR_ERR(espi->regs); -+ } -+ -+ espi->irq = platform_get_irq(pdev, 0); -+ if (espi->irq < 0) { -+ dev_err(dev, "cannot get IRQ number\n"); -+ return -ENODEV; -+ } -+ -+ espi->rst = devm_reset_control_get_optional(&pdev->dev, NULL); -+ if (IS_ERR(espi->rst)) { -+ dev_err(dev, "cannot get reset control\n"); -+ return PTR_ERR(espi->rst); -+ } -+ -+ espi->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(espi->clk)) { -+ dev_err(dev, "cannot get clock control\n"); -+ return PTR_ERR(espi->clk); -+ } -+ -+ rc = clk_prepare_enable(espi->clk); -+ if (rc) { -+ dev_err(dev, "cannot enable clocks\n"); -+ return rc; -+ } -+ -+ espi->ops->espi_pre_init(espi); -+ -+ rc = espi->ops->espi_perif_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); -+ return rc; -+ } -+ -+ rc = espi->ops->espi_vw_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init vw channel, rc=%d\n", rc); -+ goto err_remove_perif; -+ } -+ -+ rc = espi->ops->espi_oob_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init oob channel, rc=%d\n", rc); -+ goto err_remove_vw; -+ } -+ -+ rc = espi->ops->espi_flash_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init flash channel, rc=%d\n", rc); -+ goto err_remove_oob; -+ } -+ -+ rc = devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, -+ dev_name(dev), espi); -+ if (rc) { -+ dev_err(dev, "cannot request IRQ\n"); -+ goto err_remove_flash; -+ } -+ -+ if (espi->perif.mmbi.enable) { -+ rc = devm_request_irq(dev, espi->perif.mmbi.irq, -+ espi->perif.mmbi.mmbi_isr, 0, dev_name(dev), -+ espi); -+ if (rc) { -+ dev_err(dev, "cannot request MMBI IRQ\n"); -+ goto err_remove_flash; -+ } -+ } -+ -+ espi->ops->espi_post_init(espi); -+ -+ platform_set_drvdata(pdev, espi); -+ -+ dev_info(dev, "module loaded\n"); -+ -+ return 0; -+ -+err_remove_flash: -+ espi->ops->espi_flash_remove(espi); -+err_remove_oob: -+ espi->ops->espi_oob_remove(espi); -+err_remove_vw: -+ espi->ops->espi_vw_remove(espi); -+err_remove_perif: -+ espi->ops->espi_perif_remove(espi); -+ -+ return rc; -+} -+ -+static void aspeed_espi_remove(struct platform_device *pdev) -+{ -+ struct aspeed_espi *espi; -+ struct device *dev; -+ -+ dev = &pdev->dev; -+ -+ espi = dev_get_drvdata(dev); -+ -+ espi->ops->espi_deinit(espi); -+ -+ if (espi->ops->espi_perif_remove(espi)) -+ dev_warn(dev, "cannot remove peripheral channel\n"); -+ if (espi->ops->espi_vw_remove(espi)) -+ dev_warn(dev, "cannot remove vw channel\n"); -+ if (espi->ops->espi_oob_remove(espi)) -+ dev_warn(dev, "cannot remove oob channel\n"); -+ if (espi->ops->espi_flash_remove(espi)) -+ dev_warn(dev, "cannot remove flash channel\n"); -+} -+ -+static struct platform_driver aspeed_espi_driver = { -+ .driver = { -+ .name = "aspeed-espi", -+ .of_match_table = aspeed_espi_of_matches, -+ }, -+ .probe = aspeed_espi_probe, -+ .remove = aspeed_espi_remove, -+}; -+ -+module_platform_driver(aspeed_espi_driver); -+ -+MODULE_AUTHOR("Aspeed Technology Inc."); -+MODULE_DESCRIPTION("Aspeed eSPI controller (AST2500/2600/2700)"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/espi/aspeed-espi.h -new file mode 100644 -index 000000000..6a8570e30 ---- /dev/null -+++ b/drivers/soc/aspeed/espi/aspeed-espi.h -@@ -0,0 +1,227 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Unified eSPI driver header file and data structures -+ * Copyright 2026 Aspeed Technology Inc. -+ */ -+#ifndef __ASPEED_ESPI_H__ -+#define __ASPEED_ESPI_H__ -+ -+#include "linux/platform_device.h" -+#include -+#include -+#include -+ -+#define PERIF_MMBI_INST_NUM 8 -+#define DEVICE_NAME "aspeed-espi" -+ -+enum aspeed_espi_platform_id { -+ ASPEED_ESPI_PLATFORM_ID_AST2500 = 0x2500, -+ ASPEED_ESPI_PLATFORM_ID_AST2600 = 0x2600, -+ ASPEED_ESPI_PLATFORM_ID_AST2700 = 0x2700, -+}; -+ -+/* consistent with DTS property "flash-safs-mode" */ -+enum aspeed_edaf_mode { -+ EDAF_MODE_MIX = 0x0, -+ EDAF_MODE_SW, -+ EDAF_MODE_HW, -+ EDAF_MODES, -+}; -+ -+struct aspeed_espi_perif; -+ -+struct aspeed_espi_perif_mmbi { -+ void *b2h_virt; -+ void *h2b_virt; -+ dma_addr_t b2h_addr; -+ dma_addr_t h2b_addr; -+ struct miscdevice b2h_mdev; -+ struct miscdevice h2b_mdev; -+ bool host_rwp_update; -+ wait_queue_head_t wq; -+ struct aspeed_espi_perif *perif; -+}; -+ -+struct aspeed_espi_perif { -+ struct { -+ bool enable; -+ int irq; -+ void *virt; -+ dma_addr_t taddr; -+ dma_addr_t saddr; -+ resource_size_t size; -+ u32 inst_num; -+ u32 inst_size; -+ irqreturn_t (*mmbi_isr)(int irq, void *espi); -+ struct aspeed_espi_perif_mmbi inst[PERIF_MMBI_INST_NUM]; -+ } mmbi; -+ -+ struct { -+ bool enable; -+ void *virt; -+ dma_addr_t taddr; -+ dma_addr_t saddr; -+ resource_size_t size; -+ } mcyc; -+ -+ struct { -+ bool enable; -+ void *np_tx_virt; -+ dma_addr_t np_tx_addr; -+ void *pc_tx_virt; -+ dma_addr_t pc_tx_addr; -+ void *pc_rx_virt; -+ dma_addr_t pc_rx_addr; -+ } dma; -+ -+ bool rtc_enable; -+ bool rx_ready; -+ wait_queue_head_t wq; -+ -+ spinlock_t lock; // protects rx_ready -+ struct mutex np_tx_mtx; // protects np_tx_virt/addr -+ struct mutex pc_tx_mtx; // protects pc_tx_virt/addr -+ struct mutex pc_rx_mtx; // protects pc_rx_virt/addr -+ -+ struct miscdevice mdev; -+}; -+ -+struct aspeed_espi_vw { -+ struct { -+ bool hw_mode; -+ u32 grp; -+ u32 dir0; -+ u32 dir1; -+ u32 val0; -+ u32 val1; -+ } gpio; -+ -+ struct { -+ bool enabled; -+ spinlock_t pltrst_lock; // protects pltrst_status -+ wait_queue_head_t pltrst_wq; -+ char pltrst_status; -+ bool pltrst_avail; -+ } pltrst; -+ -+ struct miscdevice pltrst_mdev; -+ struct miscdevice mdev; -+}; -+ -+struct ast2700_espi_oob_dma_tx_desc { -+ u32 data_addrl; -+ u32 data_addrh; -+ u8 cyc; -+ u16 tag : 4; -+ u16 len : 12; -+ u8 msg_type : 3; -+ u8 raz0 : 1; -+ u8 pec : 1; -+ u8 int_en : 1; -+ u8 pause : 1; -+ u8 raz1 : 1; -+ u32 raz2; -+ u32 raz3; -+ u32 pad[3]; -+} __packed; -+ -+struct ast2700_espi_oob_dma_rx_desc { -+ u32 data_addrl; -+ u32 data_addrh; -+ u8 cyc; -+ u16 tag : 4; -+ u16 len : 12; -+ u8 raz : 7; -+ u8 dirty : 1; -+ u32 pad; -+} __packed; -+ -+struct ast2600_espi_oob_dma_tx_desc { -+ u32 data_addr; -+ u8 cyc; -+ u16 tag : 4; -+ u16 len : 12; -+ u8 msg_type : 3; -+ u8 raz0 : 1; -+ u8 pec : 1; -+ u8 int_en : 1; -+ u8 pause : 1; -+ u8 raz1 : 1; -+ u32 raz2; -+ u32 raz3; -+} __packed; -+ -+struct ast2600_espi_oob_dma_rx_desc { -+ u32 data_addr; -+ u8 cyc; -+ u16 tag : 4; -+ u16 len : 12; -+ u8 raz : 7; -+ u8 dirty : 1; -+} __packed; -+ -+struct aspeed_espi_oob { -+ struct { -+ bool enable; -+ void *txd_virt; -+ dma_addr_t txd_addr; -+ void *rxd_virt; -+ dma_addr_t rxd_addr; -+ void *tx_virt; -+ dma_addr_t tx_addr; -+ void *rx_virt; -+ dma_addr_t rx_addr; -+ } dma; -+ -+ bool rx_ready; -+ wait_queue_head_t wq; -+ -+ spinlock_t lock; // protects rx_ready -+ struct mutex tx_mtx; // protects tx_virt/addr -+ struct mutex rx_mtx; // protects rx_virt/addr -+ -+ struct miscdevice mdev; -+}; -+ -+struct aspeed_espi_flash { -+ struct { -+ u32 mode; -+ phys_addr_t taddr; -+ resource_size_t size; -+ } edaf; -+ -+ struct { -+ bool enable; -+ void *tx_virt; -+ dma_addr_t tx_addr; -+ void *rx_virt; -+ dma_addr_t rx_addr; -+ } dma; -+ -+ bool rx_ready; -+ wait_queue_head_t wq; -+ -+ spinlock_t lock; // protects rx_ready -+ struct mutex rx_mtx; // protects rx_virt/addr -+ struct mutex tx_mtx; // protects tx_virt/addr -+ -+ struct miscdevice mdev; -+}; -+ -+struct aspeed_espi { -+ struct platform_device *pdev; -+ struct device *dev; -+ void __iomem *regs; -+ struct reset_control *rst; -+ struct clk *clk; -+ int dev_id; -+ int irq; -+ -+ struct aspeed_espi_perif perif; -+ struct aspeed_espi_vw vw; -+ struct aspeed_espi_oob oob; -+ struct aspeed_espi_flash flash; -+ const struct aspeed_espi_ops *ops; -+}; -+ -+#endif // __ASPEED_ESPI_H__ -diff --git a/drivers/soc/aspeed/ast2500-espi.c b/drivers/soc/aspeed/espi/ast2500-espi.c -similarity index 77% -rename from drivers/soc/aspeed/ast2500-espi.c -rename to drivers/soc/aspeed/espi/ast2500-espi.c -index a9de566f7..690eb5050 100644 ---- a/drivers/soc/aspeed/ast2500-espi.c -+++ b/drivers/soc/aspeed/espi/ast2500-espi.c -@@ -3,6 +3,7 @@ - * Copyright 2023 Aspeed Technology Inc. - */ - #include -+#include - #include - #include - #include -@@ -19,123 +20,28 @@ - #include - - #include "ast2500-espi.h" -- --#define DEVICE_NAME "aspeed-espi" -+#include "aspeed-espi-comm.h" -+#include "aspeed-espi.h" - - #define PERIF_MCYC_UNLOCK 0xfedc756e - #define PERIF_MCYC_ALIGN SZ_64K - - #define FLASH_SAFS_ALIGN SZ_16M - --struct ast2500_espi_perif { -- struct { -- bool enable; -- void *virt; -- dma_addr_t taddr; -- uint32_t saddr; -- uint32_t size; -- } mcyc; -- -- struct { -- bool enable; -- void *np_tx_virt; -- dma_addr_t np_tx_addr; -- void *pc_tx_virt; -- dma_addr_t pc_tx_addr; -- void *pc_rx_virt; -- dma_addr_t pc_rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex np_tx_mtx; -- struct mutex pc_tx_mtx; -- struct mutex pc_rx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2500_espi_vw { -- struct { -- bool hw_mode; -- uint32_t val; -- } gpio; -- -- struct miscdevice mdev; --}; -- --struct ast2500_espi_oob { -- struct { -- bool enable; -- void *tx_virt; -- dma_addr_t tx_addr; -- void *rx_virt; -- dma_addr_t rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex tx_mtx; -- struct mutex rx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2500_espi_flash { -- struct { -- uint32_t mode; -- phys_addr_t taddr; -- uint32_t size; -- } safs; -- -- struct { -- bool enable; -- void *tx_virt; -- dma_addr_t tx_addr; -- void *rx_virt; -- dma_addr_t rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex rx_mtx; -- struct mutex tx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2500_espi { -- struct device *dev; -- void __iomem *regs; -- struct clk *clk; -- int irq; -- -- struct ast2500_espi_perif perif; -- struct ast2500_espi_vw vw; -- struct ast2500_espi_oob oob; -- struct ast2500_espi_flash flash; --}; -- - /* peripheral channel (CH0) */ - static long ast2500_espi_perif_pc_get_rx(struct file *fp, -- struct ast2500_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2500_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&perif->pc_rx_mtx)) -@@ -243,16 +149,16 @@ static long ast2500_espi_perif_pc_get_rx(struct file *fp, - } - - static long ast2500_espi_perif_pc_put_tx(struct file *fp, -- struct ast2500_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2500_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (!mutex_trylock(&perif->pc_tx_mtx)) - return -EAGAIN; -@@ -310,16 +216,16 @@ static long ast2500_espi_perif_pc_put_tx(struct file *fp, - } - - static long ast2500_espi_perif_np_put_tx(struct file *fp, -- struct ast2500_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2500_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (!mutex_trylock(&perif->np_tx_mtx)) - return -EAGAIN; -@@ -378,10 +284,10 @@ static long ast2500_espi_perif_np_put_tx(struct file *fp, - - static long ast2500_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2500_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct aspeed_espi_ioc ioc; - -- perif = container_of(fp->private_data, struct ast2500_espi_perif, mdev); -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -405,11 +311,11 @@ static long ast2500_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned - - static int ast2500_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2500_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - unsigned long vm_size; - pgprot_t vm_prot; - -- perif = container_of(fp->private_data, struct ast2500_espi_perif, mdev); -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); - if (!perif->mcyc.enable) - return -EPERM; - -@@ -435,11 +341,11 @@ static const struct file_operations ast2500_espi_perif_fops = { - .unlocked_ioctl = ast2500_espi_perif_ioctl, - }; - --static void ast2500_espi_perif_isr(struct ast2500_espi *espi) -+static void ast2500_espi_perif_isr(struct aspeed_espi *espi) - { -- struct ast2500_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - perif = &espi->perif; - -@@ -456,11 +362,11 @@ static void ast2500_espi_perif_isr(struct ast2500_espi *espi) - } - } - --static void ast2500_espi_perif_reset(struct ast2500_espi *espi) -+static void ast2500_espi_perif_reset(struct aspeed_espi *espi) - { -- struct ast2500_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct device *dev; -- uint32_t reg, mask; -+ u32 reg, mask; - - dev = espi->dev; - -@@ -518,9 +424,9 @@ static void ast2500_espi_perif_reset(struct ast2500_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2500_espi_perif_probe(struct ast2500_espi *espi) -+int ast2500_espi_perif_probe(struct aspeed_espi *espi) - { -- struct ast2500_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct device *dev; - int rc; - -@@ -538,13 +444,13 @@ static int ast2500_espi_perif_probe(struct ast2500_espi *espi) - - perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); - if (perif->mcyc.enable) { -- rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", &perif->mcyc.saddr); -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", (u32 *)&perif->mcyc.saddr); - if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); - return -ENODEV; - } - -- rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", &perif->mcyc.size); -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", (u32 *)&perif->mcyc.size); - if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); - return -EINVAL; -@@ -597,11 +503,11 @@ static int ast2500_espi_perif_probe(struct ast2500_espi *espi) - return 0; - } - --static int ast2500_espi_perif_remove(struct ast2500_espi *espi) -+int ast2500_espi_perif_remove(struct aspeed_espi *espi) - { -- struct ast2500_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -643,21 +549,21 @@ static int ast2500_espi_perif_remove(struct ast2500_espi *espi) - /* virtual wire channel (CH1) */ - static long ast2500_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2500_espi_vw *vw; -- struct ast2500_espi *espi; -- uint32_t gpio; -+ struct aspeed_espi_vw *vw; -+ struct aspeed_espi *espi; -+ u32 gpio; - -- vw = container_of(fp->private_data, struct ast2500_espi_vw, mdev); -- espi = container_of(vw, struct ast2500_espi, vw); -- gpio = vw->gpio.val; -+ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); -+ espi = container_of(vw, struct aspeed_espi, vw); -+ gpio = vw->gpio.val0; - - switch (cmd) { - case ASPEED_ESPI_VW_GET_GPIO_VAL: -- if (put_user(gpio, (uint32_t __user *)arg)) -+ if (put_user(gpio, (u32 __user *)arg)) - return -EFAULT; - break; - case ASPEED_ESPI_VW_PUT_GPIO_VAL: -- if (get_user(gpio, (uint32_t __user *)arg)) -+ if (get_user(gpio, (u32 __user *)arg)) - return -EFAULT; - - writel(gpio, espi->regs + ESPI_VW_GPIO_VAL); -@@ -674,10 +580,10 @@ static const struct file_operations ast2500_espi_vw_fops = { - .unlocked_ioctl = ast2500_espi_vw_ioctl, - }; - --static void ast2500_espi_vw_isr(struct ast2500_espi *espi) -+static void ast2500_espi_vw_isr(struct aspeed_espi *espi) - { -- struct ast2500_espi_vw *vw; -- uint32_t reg, sts, sts_sysevt; -+ struct aspeed_espi_vw *vw; -+ u32 reg, sts, sts_sysevt; - - vw = &espi->vw; - -@@ -714,22 +620,22 @@ static void ast2500_espi_vw_isr(struct ast2500_espi *espi) - } - - if (sts & ESPI_INT_STS_VW_GPIO) { -- vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); - writel(ESPI_INT_STS_VW_GPIO, espi->regs + ESPI_INT_STS); - } - } - --static void ast2500_espi_vw_reset(struct ast2500_espi *espi) -+static void ast2500_espi_vw_reset(struct aspeed_espi *espi) - { -- uint32_t reg; -- struct ast2500_espi_vw *vw = &espi->vw; -+ u32 reg; -+ struct aspeed_espi_vw *vw = &espi->vw; - - reg = readl(espi->regs + ESPI_INT_EN); - reg &= ~(ESPI_INT_EN_VW); - writel(reg, espi->regs + ESPI_INT_EN); - writel(ESPI_INT_STS_VW, espi->regs + ESPI_INT_STS); - -- vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); - - /* Host Reset Warn and OOB Reset Warn system events */ - reg = readl(espi->regs + ESPI_VW_SYSEVT_INT_T2) -@@ -766,11 +672,11 @@ static void ast2500_espi_vw_reset(struct ast2500_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2500_espi_vw_probe(struct ast2500_espi *espi) -+int ast2500_espi_vw_probe(struct aspeed_espi *espi) - { - int rc; - struct device *dev = espi->dev; -- struct ast2500_espi_vw *vw = &espi->vw; -+ struct aspeed_espi_vw *vw = &espi->vw; - - writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_EN); - writel(0xffffffff, espi->regs + ESPI_VW_SYSEVT_INT_STS); -@@ -795,10 +701,10 @@ static int ast2500_espi_vw_probe(struct ast2500_espi *espi) - return 0; - } - --static int ast2500_espi_vw_remove(struct ast2500_espi *espi) -+int ast2500_espi_vw_remove(struct aspeed_espi *espi) - { -- struct ast2500_espi_vw *vw; -- uint32_t reg; -+ struct aspeed_espi_vw *vw; -+ u32 reg; - - vw = &espi->vw; - -@@ -813,18 +719,18 @@ static int ast2500_espi_vw_remove(struct ast2500_espi *espi) - - /* out-of-band channel (CH2) */ - static long ast2500_espi_oob_get_rx(struct file *fp, -- struct ast2500_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - -- espi = container_of(oob, struct ast2500_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&oob->rx_mtx)) -@@ -910,16 +816,16 @@ static long ast2500_espi_oob_get_rx(struct file *fp, - } - - static long ast2500_espi_oob_put_tx(struct file *fp, -- struct ast2500_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(oob, struct ast2500_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - if (!mutex_trylock(&oob->tx_mtx)) - return -EAGAIN; -@@ -983,10 +889,10 @@ static long ast2500_espi_oob_put_tx(struct file *fp, - - static long ast2500_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2500_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct aspeed_espi_ioc ioc; - -- oob = container_of(fp->private_data, struct ast2500_espi_oob, mdev); -+ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -1011,11 +917,11 @@ static const struct file_operations ast2500_espi_oob_fops = { - .unlocked_ioctl = ast2500_espi_oob_ioctl, - }; - --static void ast2500_espi_oob_isr(struct ast2500_espi *espi) -+static void ast2500_espi_oob_isr(struct aspeed_espi *espi) - { -- struct ast2500_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - oob = &espi->oob; - -@@ -1032,10 +938,10 @@ static void ast2500_espi_oob_isr(struct ast2500_espi *espi) - } - } - --static void ast2500_espi_oob_reset(struct ast2500_espi *espi) -+static void ast2500_espi_oob_reset(struct aspeed_espi *espi) - { -- struct ast2500_espi_oob *oob; -- uint32_t reg; -+ struct aspeed_espi_oob *oob; -+ u32 reg; - - oob = &espi->oob; - -@@ -1074,9 +980,9 @@ static void ast2500_espi_oob_reset(struct ast2500_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2500_espi_oob_probe(struct ast2500_espi *espi) -+int ast2500_espi_oob_probe(struct aspeed_espi *espi) - { -- struct ast2500_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct device *dev; - int rc; - -@@ -1121,11 +1027,11 @@ static int ast2500_espi_oob_probe(struct ast2500_espi *espi) - return 0; - } - --static int ast2500_espi_oob_remove(struct ast2500_espi *espi) -+int ast2500_espi_oob_remove(struct aspeed_espi *espi) - { -- struct ast2500_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -1156,20 +1062,20 @@ static int ast2500_espi_oob_remove(struct ast2500_espi *espi) - - /* flash channel (CH3) */ - static long ast2500_espi_flash_get_rx(struct file *fp, -- struct ast2500_espi_flash *flash, -+ struct aspeed_espi_flash *flash, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - - rc = 0; - -- espi = container_of(flash, struct ast2500_espi, flash); -+ espi = container_of(flash, struct aspeed_espi, flash); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&flash->rx_mtx)) -@@ -1278,16 +1184,16 @@ static long ast2500_espi_flash_get_rx(struct file *fp, - } - - static long ast2500_espi_flash_put_tx(struct file *fp, -- struct ast2500_espi_flash *flash, -+ struct aspeed_espi_flash *flash, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2500_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(flash, struct ast2500_espi, flash); -+ espi = container_of(flash, struct aspeed_espi, flash); - - if (!mutex_trylock(&flash->tx_mtx)) - return -EAGAIN; -@@ -1346,10 +1252,10 @@ static long ast2500_espi_flash_put_tx(struct file *fp, - - static long ast2500_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2500_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct aspeed_espi_ioc ioc; - -- flash = container_of(fp->private_data, struct ast2500_espi_flash, mdev); -+ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -1374,11 +1280,11 @@ static const struct file_operations ast2500_espi_flash_fops = { - .unlocked_ioctl = ast2500_espi_flash_ioctl, - }; - --static void ast2500_espi_flash_isr(struct ast2500_espi *espi) -+static void ast2500_espi_flash_isr(struct aspeed_espi *espi) - { -- struct ast2500_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - flash = &espi->flash; - -@@ -1395,10 +1301,10 @@ static void ast2500_espi_flash_isr(struct ast2500_espi *espi) - } - } - --static void ast2500_espi_flash_reset(struct ast2500_espi *espi) -+static void ast2500_espi_flash_reset(struct aspeed_espi *espi) - { -- struct ast2500_espi_flash *flash = &espi->flash; -- uint32_t reg; -+ struct aspeed_espi_flash *flash = &espi->flash; -+ u32 reg; - - reg = readl(espi->regs + ESPI_INT_EN); - reg &= ~(ESPI_INT_EN_FLASH); -@@ -1418,9 +1324,9 @@ static void ast2500_espi_flash_reset(struct ast2500_espi *espi) - reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); - writel(reg, espi->regs + ESPI_CTRL); - -- if (flash->safs.mode == SAFS_MODE_MIX) { -- reg = FIELD_PREP(ESPI_FLASH_SAFS_TADDR_BASE, flash->safs.taddr >> 24) -- | FIELD_PREP(ESPI_FLASH_SAFS_TADDR_MASK, (~(flash->safs.size - 1)) >> 24); -+ if (flash->edaf.mode == EDAF_MODE_MIX) { -+ reg = FIELD_PREP(ESPI_FLASH_SAFS_TADDR_BASE, flash->edaf.taddr >> 24) -+ | FIELD_PREP(ESPI_FLASH_SAFS_TADDR_MASK, (~(flash->edaf.size - 1)) >> 24); - writel(reg, espi->regs + ESPI_FLASH_SAFS_TADDR); - } else { - reg = readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SAFS_SW_MODE; -@@ -1444,9 +1350,9 @@ static void ast2500_espi_flash_reset(struct ast2500_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2500_espi_flash_probe(struct ast2500_espi *espi) -+int ast2500_espi_flash_probe(struct aspeed_espi *espi) - { -- struct ast2500_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct device *dev; - int rc; - -@@ -1461,18 +1367,18 @@ static int ast2500_espi_flash_probe(struct ast2500_espi *espi) - mutex_init(&flash->tx_mtx); - mutex_init(&flash->rx_mtx); - -- flash->safs.mode = SAFS_MODE_MIX; -+ flash->edaf.mode = EDAF_MODE_MIX; - -- of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->safs.mode); -- if (flash->safs.mode == SAFS_MODE_MIX) { -- rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", &flash->safs.taddr); -- if (rc || !IS_ALIGNED(flash->safs.taddr, FLASH_SAFS_ALIGN)) { -+ of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->edaf.mode); -+ if (flash->edaf.mode == EDAF_MODE_MIX) { -+ rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", (u32 *)&flash->edaf.taddr); -+ if (rc || !IS_ALIGNED(flash->edaf.taddr, FLASH_SAFS_ALIGN)) { - dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); - return -ENODEV; - } - -- rc = of_property_read_u32(dev->of_node, "flash-safs-size", &flash->safs.size); -- if (rc || !IS_ALIGNED(flash->safs.size, FLASH_SAFS_ALIGN)) { -+ rc = of_property_read_u32(dev->of_node, "flash-safs-size", (u32 *)&flash->edaf.size); -+ if (rc || !IS_ALIGNED(flash->edaf.size, FLASH_SAFS_ALIGN)) { - dev_err(dev, "cannot get 16MB-aligned SAFS size\n"); - return -ENODEV; - } -@@ -1508,11 +1414,11 @@ static int ast2500_espi_flash_probe(struct ast2500_espi *espi) - return 0; - } - --static int ast2500_espi_flash_remove(struct ast2500_espi *espi) -+int ast2500_espi_flash_remove(struct aspeed_espi *espi) - { -- struct ast2500_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -1542,12 +1448,12 @@ static int ast2500_espi_flash_remove(struct ast2500_espi *espi) - } - - /* global control */ --static irqreturn_t ast2500_espi_isr(int irq, void *arg) -+irqreturn_t ast2500_espi_isr(int irq, void *arg) - { -- struct ast2500_espi *espi; -- uint32_t sts; -+ struct aspeed_espi *espi; -+ u32 sts; - -- espi = (struct ast2500_espi *)arg; -+ espi = (struct aspeed_espi *)arg; - - sts = readl(espi->regs + ESPI_INT_STS); - if (!sts) -@@ -1576,164 +1482,29 @@ static irqreturn_t ast2500_espi_isr(int irq, void *arg) - return IRQ_HANDLED; - } - --static int ast2500_espi_probe(struct platform_device *pdev) -+void ast2500_espi_pre_init(struct aspeed_espi *espi) - { -- struct ast2500_espi *espi; -- struct resource *res; -- struct device *dev; -- uint32_t reg; -- int rc; -- -- dev = &pdev->dev; -- -- espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -- if (!espi) -- return -ENOMEM; -- -- espi->dev = dev; -- -- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -- if (rc) { -- dev_err(dev, "cannot set 64-bits DMA mask\n"); -- return rc; -- } -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!res) { -- dev_err(dev, "cannot get resource\n"); -- return -ENODEV; -- } -- -- espi->regs = devm_ioremap_resource(dev, res); -- if (IS_ERR(espi->regs)) { -- dev_err(dev, "cannot map registers\n"); -- return PTR_ERR(espi->regs); -- } -- -- espi->irq = platform_get_irq(pdev, 0); -- if (espi->irq < 0) { -- dev_err(dev, "cannot get IRQ number\n"); -- return -ENODEV; -- } -- -- espi->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(espi->clk)) { -- dev_err(dev, "cannot get clock control\n"); -- return PTR_ERR(espi->clk); -- } -- -- rc = clk_prepare_enable(espi->clk); -- if (rc) { -- dev_err(dev, "cannot enable clocks\n"); -- return rc; -- } -+ u32 reg; - - reg = readl(espi->regs + ESPI_INT_EN); - reg &= ~ESPI_INT_EN_RST_DEASSERT; - writel(reg, espi->regs + ESPI_INT_EN); -+} - -- rc = ast2500_espi_perif_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); -- return rc; -- } -- -- rc = ast2500_espi_vw_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init vw channel, rc=%d\n", rc); -- goto err_remove_perif; -- } -- -- rc = ast2500_espi_oob_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init oob channel, rc=%d\n", rc); -- goto err_remove_vw; -- } -- -- rc = ast2500_espi_flash_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init flash channel, rc=%d\n", rc); -- goto err_remove_oob; -- } -- -- rc = devm_request_irq(dev, espi->irq, ast2500_espi_isr, 0, dev_name(dev), espi); -- if (rc) { -- dev_err(dev, "cannot request IRQ\n"); -- goto err_remove_flash; -- } -+void ast2500_espi_post_init(struct aspeed_espi *espi) -+{ -+ u32 reg; - - reg = readl(espi->regs + ESPI_INT_EN); - reg |= ESPI_INT_EN_RST_DEASSERT; - writel(reg, espi->regs + ESPI_INT_EN); -- -- dev_set_drvdata(dev, espi); -- -- dev_info(dev, "module loaded\n"); -- -- return 0; -- --err_remove_flash: -- ast2500_espi_flash_remove(espi); --err_remove_oob: -- ast2500_espi_oob_remove(espi); --err_remove_vw: -- ast2500_espi_vw_remove(espi); --err_remove_perif: -- ast2500_espi_perif_remove(espi); -- -- return rc; - } - --static int ast2500_espi_remove(struct platform_device *pdev) -+void ast2500_espi_deinit(struct aspeed_espi *espi) - { -- struct ast2500_espi *espi; -- struct device *dev; -- uint32_t reg; -- int rc; -- -- dev = &pdev->dev; -- -- espi = (struct ast2500_espi *)dev_get_drvdata(dev); -+ u32 reg; - - reg = readl(espi->regs + ESPI_INT_EN); - reg &= ~(ESPI_INT_EN_RST_DEASSERT); - writel(reg, espi->regs + ESPI_INT_EN); -- -- rc = ast2500_espi_perif_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2500_espi_vw_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2500_espi_oob_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2500_espi_flash_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- return 0; - } -- --static const struct of_device_id ast2500_espi_of_matches[] = { -- { .compatible = "aspeed,ast2500-espi" }, -- { }, --}; -- --static struct platform_driver ast2500_espi_driver = { -- .driver = { -- .name = "ast2500-espi", -- .of_match_table = ast2500_espi_of_matches, -- }, -- .probe = ast2500_espi_probe, -- .remove = ast2500_espi_remove, --}; -- --module_platform_driver(ast2500_espi_driver); -- --MODULE_AUTHOR("Chia-Wei Wang "); --MODULE_DESCRIPTION("Control of AST2500 eSPI Device"); --MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2500-espi.h b/drivers/soc/aspeed/espi/ast2500-espi.h -similarity index 91% -rename from drivers/soc/aspeed/ast2500-espi.h -rename to drivers/soc/aspeed/espi/ast2500-espi.h -index b4ee0bc25..34f4f9ccb 100644 ---- a/drivers/soc/aspeed/ast2500-espi.h -+++ b/drivers/soc/aspeed/espi/ast2500-espi.h -@@ -1,12 +1,14 @@ - /* SPDX-License-Identifier: GPL-2.0+ */ - /* -+ * Register definitions for Aspeed AST2500 eSPI controller - * Copyright 2023 Aspeed Technology Inc. - */ - #ifndef _AST2500_ESPI_H_ - #define _AST2500_ESPI_H_ - - #include --#include "aspeed-espi-comm.h" -+#include -+#include "aspeed-espi.h" - - /* registers */ - #define ESPI_CTRL 0x000 -@@ -240,11 +242,17 @@ - ESPI_INT_STS_FLASH_TX_CMPLT | \ - ESPI_INT_STS_FLASH_RX_CMPLT) - --/* consistent with DTS property "flash-safs-mode" */ --enum ast2500_safs_mode { -- SAFS_MODE_MIX = 0x0, -- SAFS_MODE_SW, -- SAFS_MODES, --}; -- -+/* operators for framework initialization */ -+void ast2500_espi_pre_init(struct aspeed_espi *espi); -+void ast2500_espi_post_init(struct aspeed_espi *espi); -+void ast2500_espi_deinit(struct aspeed_espi *espi); -+int ast2500_espi_perif_probe(struct aspeed_espi *espi); -+int ast2500_espi_perif_remove(struct aspeed_espi *espi); -+int ast2500_espi_vw_probe(struct aspeed_espi *espi); -+int ast2500_espi_vw_remove(struct aspeed_espi *espi); -+int ast2500_espi_oob_probe(struct aspeed_espi *espi); -+int ast2500_espi_oob_remove(struct aspeed_espi *espi); -+int ast2500_espi_flash_probe(struct aspeed_espi *espi); -+int ast2500_espi_flash_remove(struct aspeed_espi *espi); -+irqreturn_t ast2500_espi_isr(int irq, void *arg); - #endif -diff --git a/drivers/soc/aspeed/ast2600-espi.c b/drivers/soc/aspeed/espi/ast2600-espi.c -similarity index 75% -rename from drivers/soc/aspeed/ast2600-espi.c -rename to drivers/soc/aspeed/espi/ast2600-espi.c -index fd134afa9..5e8abae4e 100644 ---- a/drivers/soc/aspeed/ast2600-espi.c -+++ b/drivers/soc/aspeed/espi/ast2600-espi.c -@@ -21,8 +21,8 @@ - #include - - #include "ast2600-espi.h" -- --#define DEVICE_NAME "aspeed-espi" -+#include "aspeed-espi-comm.h" -+#include "aspeed-espi.h" - - #define PERIF_MCYC_ALIGN SZ_64K - #define PERIF_MMBI_ALIGN SZ_64K -@@ -32,170 +32,22 @@ - #define OOB_DMA_DESC_NUM 8 - #define OOB_DMA_DESC_CUSTOM 0x4 - --#define FLASH_SAFS_ALIGN SZ_16M -- --struct ast2600_espi_perif_mmbi { -- void *b2h_virt; -- void *h2b_virt; -- dma_addr_t b2h_addr; -- dma_addr_t h2b_addr; -- struct miscdevice b2h_mdev; -- struct miscdevice h2b_mdev; -- bool host_rwp_update; -- wait_queue_head_t wq; -- struct ast2600_espi_perif *perif; --}; -- --struct ast2600_espi_perif { -- struct { -- bool enable; -- int irq; -- void *virt; -- dma_addr_t taddr; -- uint32_t saddr; -- uint32_t size; -- uint32_t inst_size; -- struct ast2600_espi_perif_mmbi inst[PERIF_MMBI_INST_NUM]; -- } mmbi; -- -- struct { -- bool enable; -- void *virt; -- dma_addr_t taddr; -- uint32_t saddr; -- uint32_t size; -- } mcyc; -- -- struct { -- bool enable; -- void *np_tx_virt; -- dma_addr_t np_tx_addr; -- void *pc_tx_virt; -- dma_addr_t pc_tx_addr; -- void *pc_rx_virt; -- dma_addr_t pc_rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex np_tx_mtx; -- struct mutex pc_tx_mtx; -- struct mutex pc_rx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2600_espi_vw { -- struct { -- bool hw_mode; -- uint32_t dir; -- uint32_t val; -- } gpio; -- -- struct miscdevice mdev; --}; -- --struct ast2600_espi_oob_dma_tx_desc { -- uint32_t data_addr; -- uint8_t cyc; -- uint16_t tag : 4; -- uint16_t len : 12; -- uint8_t msg_type : 3; -- uint8_t raz0 : 1; -- uint8_t pec : 1; -- uint8_t int_en : 1; -- uint8_t pause : 1; -- uint8_t raz1 : 1; -- uint32_t raz2; -- uint32_t raz3; --} __packed; -- --struct ast2600_espi_oob_dma_rx_desc { -- uint32_t data_addr; -- uint8_t cyc; -- uint16_t tag : 4; -- uint16_t len : 12; -- uint8_t raz : 7; -- uint8_t dirty : 1; --} __packed; -- --struct ast2600_espi_oob { -- struct { -- bool enable; -- struct ast2600_espi_oob_dma_tx_desc *txd_virt; -- dma_addr_t txd_addr; -- struct ast2600_espi_oob_dma_rx_desc *rxd_virt; -- dma_addr_t rxd_addr; -- void *tx_virt; -- dma_addr_t tx_addr; -- void *rx_virt; -- dma_addr_t rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex tx_mtx; -- struct mutex rx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2600_espi_flash { -- struct { -- uint32_t mode; -- phys_addr_t taddr; -- uint32_t size; -- } safs; -- -- struct { -- bool enable; -- void *tx_virt; -- dma_addr_t tx_addr; -- void *rx_virt; -- dma_addr_t rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex rx_mtx; -- struct mutex tx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2600_espi { -- struct device *dev; -- void __iomem *regs; -- struct reset_control *rst; -- struct clk *clk; -- int irq; -- -- struct ast2600_espi_perif perif; -- struct ast2600_espi_vw vw; -- struct ast2600_espi_oob oob; -- struct ast2600_espi_flash flash; --}; -+#define FLASH_EDAF_ALIGN SZ_16M - - /* peripheral channel (CH0) */ - static int ast2600_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2600_espi_perif_mmbi *mmbi; -- struct ast2600_espi_perif *perif; -- struct ast2600_espi *espi; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ struct aspeed_espi *espi; - unsigned long vm_size; - pgprot_t prot; - -- mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, b2h_mdev); -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, b2h_mdev); - - perif = mmbi->perif; - -- espi = container_of(perif, struct ast2600_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - vm_size = vma->vm_end - vma->vm_start; - prot = vma->vm_page_prot; -@@ -215,17 +67,17 @@ static int ast2600_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vm - - static int ast2600_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2600_espi_perif_mmbi *mmbi; -- struct ast2600_espi_perif *perif; -- struct ast2600_espi *espi; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ struct aspeed_espi *espi; - unsigned long vm_size; - pgprot_t prot; - -- mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, h2b_mdev); -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); - - perif = mmbi->perif; - -- espi = container_of(perif, struct ast2600_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - vm_size = vma->vm_end - vma->vm_start; - prot = vma->vm_page_prot; -@@ -245,9 +97,9 @@ static int ast2600_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vm - - static __poll_t ast2600_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) - { -- struct ast2600_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif_mmbi *mmbi; - -- mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, h2b_mdev); -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); - - poll_wait(fp, &mmbi->wq, pt); - -@@ -260,18 +112,18 @@ static __poll_t ast2600_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_st - } - - static long ast2600_espi_perif_pc_get_rx(struct file *fp, -- struct ast2600_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2600_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&perif->pc_rx_mtx)) -@@ -379,16 +231,16 @@ static long ast2600_espi_perif_pc_get_rx(struct file *fp, - } - - static long ast2600_espi_perif_pc_put_tx(struct file *fp, -- struct ast2600_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2600_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (!mutex_trylock(&perif->pc_tx_mtx)) - return -EAGAIN; -@@ -446,16 +298,16 @@ static long ast2600_espi_perif_pc_put_tx(struct file *fp, - } - - static long ast2600_espi_perif_np_put_tx(struct file *fp, -- struct ast2600_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2600_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (!mutex_trylock(&perif->np_tx_mtx)) - return -EAGAIN; -@@ -514,10 +366,10 @@ static long ast2600_espi_perif_np_put_tx(struct file *fp, - - static long ast2600_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2600_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct aspeed_espi_ioc ioc; - -- perif = container_of(fp->private_data, struct ast2600_espi_perif, mdev); -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -541,11 +393,11 @@ static long ast2600_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned - - static int ast2600_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2600_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - unsigned long vm_size; - pgprot_t vm_prot; - -- perif = container_of(fp->private_data, struct ast2600_espi_perif, mdev); -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); - if (!perif->mcyc.enable) - return -EPERM; - -@@ -584,14 +436,14 @@ static const struct file_operations ast2600_espi_perif_fops = { - - static irqreturn_t ast2600_espi_perif_mmbi_isr(int irq, void *arg) - { -- struct ast2600_espi_perif_mmbi *mmbi; -- struct ast2600_espi_perif *perif; -- struct ast2600_espi *espi; -- uint32_t sts, tmp; -- uint32_t *p; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ struct aspeed_espi *espi; -+ u32 sts, tmp; -+ u32 *p; - int i; - -- espi = (struct ast2600_espi *)arg; -+ espi = (struct aspeed_espi *)arg; - - perif = &espi->perif; - -@@ -605,7 +457,7 @@ static irqreturn_t ast2600_espi_perif_mmbi_isr(int irq, void *arg) - - mmbi = &perif->mmbi.inst[i]; - -- p = (uint32_t *)mmbi->h2b_virt; -+ p = (u32 *)mmbi->h2b_virt; - p[0] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i)); - p[1] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i) + 4); - -@@ -619,11 +471,11 @@ static irqreturn_t ast2600_espi_perif_mmbi_isr(int irq, void *arg) - return IRQ_HANDLED; - } - --static void ast2600_espi_perif_isr(struct ast2600_espi *espi) -+static void ast2600_espi_perif_isr(struct aspeed_espi *espi) - { -- struct ast2600_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - perif = &espi->perif; - -@@ -640,10 +492,10 @@ static void ast2600_espi_perif_isr(struct ast2600_espi *espi) - } - } - --static void ast2600_espi_perif_sw_reset(struct ast2600_espi *espi) -+static void ast2600_espi_perif_sw_reset(struct aspeed_espi *espi) - { - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -667,11 +519,11 @@ static void ast2600_espi_perif_sw_reset(struct ast2600_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static void ast2600_espi_perif_reset(struct ast2600_espi *espi) -+static void ast2600_espi_perif_reset(struct aspeed_espi *espi) - { -- struct ast2600_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct device *dev; -- uint32_t reg, mask; -+ u32 reg, mask; - - dev = espi->dev; - -@@ -743,10 +595,10 @@ static void ast2600_espi_perif_reset(struct ast2600_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2600_espi_perif_probe(struct ast2600_espi *espi) -+int ast2600_espi_perif_probe(struct aspeed_espi *espi) - { -- struct ast2600_espi_perif_mmbi *mmbi; -- struct ast2600_espi_perif *perif; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; - struct platform_device *pdev; - struct device *dev; - int i, rc; -@@ -765,7 +617,7 @@ static int ast2600_espi_perif_probe(struct ast2600_espi *espi) - - perif->mmbi.enable = of_property_read_bool(dev->of_node, "perif-mmbi-enable"); - if (perif->mmbi.enable) { -- pdev = container_of(dev, struct platform_device, dev); -+ pdev = espi->pdev; - - perif->mmbi.irq = platform_get_irq(pdev, 1); - if (perif->mmbi.irq < 0) { -@@ -773,13 +625,13 @@ static int ast2600_espi_perif_probe(struct ast2600_espi *espi) - return -ENODEV; - } - -- rc = of_property_read_u32(dev->of_node, "perif-mmbi-src-addr", &perif->mmbi.saddr); -+ rc = of_property_read_u32(dev->of_node, "perif-mmbi-src-addr", (u32 *)&perif->mmbi.saddr); - if (rc || !IS_ALIGNED(perif->mmbi.saddr, PERIF_MMBI_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned MMBI host address\n"); - return -ENODEV; - } - -- rc = of_property_read_u32(dev->of_node, "perif-mmbi-instance-size", &perif->mmbi.inst_size); -+ rc = of_property_read_u32(dev->of_node, "perif-mmbi-instance-size", (u32 *)&perif->mmbi.inst_size); - if (rc || perif->mmbi.inst_size >= MMBI_INST_SIZE_TYPES) { - dev_err(dev, "cannot get valid MMBI instance size\n"); - return -EINVAL; -@@ -793,6 +645,8 @@ static int ast2600_espi_perif_probe(struct ast2600_espi *espi) - return -ENOMEM; - } - -+ perif->mmbi.mmbi_isr = ast2600_espi_perif_mmbi_isr; -+ - for (i = 0; i < PERIF_MMBI_INST_NUM; ++i) { - mmbi = &perif->mmbi.inst[i]; - -@@ -834,13 +688,13 @@ static int ast2600_espi_perif_probe(struct ast2600_espi *espi) - return -EPERM; - } - -- rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", &perif->mcyc.saddr); -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", (u32 *)&perif->mcyc.saddr); - if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); - return -ENODEV; - } - -- rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", &perif->mcyc.size); -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-size", (u32 *)&perif->mcyc.size); - if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); - return -EINVAL; -@@ -890,24 +744,15 @@ static int ast2600_espi_perif_probe(struct ast2600_espi *espi) - - ast2600_espi_perif_reset(espi); - -- if (perif->mmbi.enable) { -- rc = devm_request_irq(dev, espi->perif.mmbi.irq, -- ast2600_espi_perif_mmbi_isr, 0, dev_name(dev), espi); -- if (rc) { -- dev_err(dev, "cannot request MMBI IRQ\n"); -- return rc; -- } -- } -- - return 0; - } - --static int ast2600_espi_perif_remove(struct ast2600_espi *espi) -+int ast2600_espi_perif_remove(struct aspeed_espi *espi) - { -- struct ast2600_espi_perif_mmbi *mmbi; -- struct ast2600_espi_perif *perif; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; - struct device *dev; -- uint32_t reg; -+ u32 reg; - int i; - - dev = espi->dev; -@@ -967,13 +812,13 @@ static int ast2600_espi_perif_remove(struct ast2600_espi *espi) - /* virtual wire channel (CH1) */ - static long ast2600_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2600_espi_vw *vw; -- struct ast2600_espi *espi; -- uint32_t gpio, hw_mode; -+ struct aspeed_espi_vw *vw; -+ struct aspeed_espi *espi; -+ u32 gpio, hw_mode; - -- vw = container_of(fp->private_data, struct ast2600_espi_vw, mdev); -- espi = container_of(vw, struct ast2600_espi, vw); -- gpio = vw->gpio.val; -+ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); -+ espi = container_of(vw, struct aspeed_espi, vw); -+ gpio = vw->gpio.val0; - hw_mode = vw->gpio.hw_mode; - - if (hw_mode) { -@@ -983,7 +828,7 @@ static long ast2600_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - - switch (cmd) { - case ASPEED_ESPI_VW_GET_GPIO_VAL: -- if (put_user(gpio, (uint32_t __user *)arg)) { -+ if (put_user(gpio, (u32 __user *)arg)) { - dev_err(espi->dev, "failed to get vGPIO value\n"); - return -EFAULT; - } -@@ -992,7 +837,7 @@ static long ast2600_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - break; - - case ASPEED_ESPI_VW_PUT_GPIO_VAL: -- if (get_user(gpio, (uint32_t __user *)arg)) { -+ if (get_user(gpio, (u32 __user *)arg)) { - dev_err(espi->dev, "failed to put vGPIO value\n"); - return -EFAULT; - } -@@ -1013,17 +858,17 @@ static const struct file_operations ast2600_espi_vw_fops = { - .unlocked_ioctl = ast2600_espi_vw_ioctl, - }; - --static void ast2600_espi_vw_isr(struct ast2600_espi *espi) -+static void ast2600_espi_vw_isr(struct aspeed_espi *espi) - { -- struct ast2600_espi_vw *vw; -- uint32_t sts; -+ struct aspeed_espi_vw *vw; -+ u32 sts; - - vw = &espi->vw; - - sts = readl(espi->regs + ESPI_INT_STS); - - if (sts & ESPI_INT_STS_VW_GPIO) { -- vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); - writel(ESPI_INT_STS_VW_GPIO, espi->regs + ESPI_INT_STS); - } else if (sts & ESPI_INT_STS_VW_SYSEVT) { - /* Handle system event */ -@@ -1034,17 +879,17 @@ static void ast2600_espi_vw_isr(struct ast2600_espi *espi) - } - } - --static void ast2600_espi_vw_reset(struct ast2600_espi *espi) -+static void ast2600_espi_vw_reset(struct aspeed_espi *espi) - { -- uint32_t reg; -- struct ast2600_espi_vw *vw = &espi->vw; -+ u32 reg; -+ struct aspeed_espi_vw *vw = &espi->vw; - - writel(ESPI_INT_EN_VW, espi->regs + ESPI_INT_EN_CLR); - writel(ESPI_INT_STS_VW, espi->regs + ESPI_INT_STS); - -- writel(vw->gpio.dir, espi->regs + ESPI_VW_GPIO_DIR); -+ writel(vw->gpio.dir0, espi->regs + ESPI_VW_GPIO_DIR); - -- vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); - - reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_VW_TX_SORT); - writel(reg, espi->regs + ESPI_CTRL2); -@@ -1068,14 +913,14 @@ static void ast2600_espi_vw_reset(struct ast2600_espi *espi) - writel(0x1, espi->regs + ESPI_VW_SYSEVT1_INT_T0); - } - --static int ast2600_espi_vw_probe(struct ast2600_espi *espi) -+int ast2600_espi_vw_probe(struct aspeed_espi *espi) - { - int rc; - struct device *dev = espi->dev; -- struct ast2600_espi_vw *vw = &espi->vw; -+ struct aspeed_espi_vw *vw = &espi->vw; - - vw->gpio.hw_mode = of_property_read_bool(dev->of_node, "vw-gpio-hw-mode"); -- of_property_read_u32(dev->of_node, "vw-gpio-direction", &vw->gpio.dir); -+ of_property_read_u32(dev->of_node, "vw-gpio-direction", &vw->gpio.dir0); - - vw->mdev.parent = dev; - vw->mdev.minor = MISC_DYNAMIC_MINOR; -@@ -1092,9 +937,9 @@ static int ast2600_espi_vw_probe(struct ast2600_espi *espi) - return 0; - } - --static int ast2600_espi_vw_remove(struct ast2600_espi *espi) -+int ast2600_espi_vw_remove(struct aspeed_espi *espi) - { -- struct ast2600_espi_vw *vw; -+ struct aspeed_espi_vw *vw; - - vw = &espi->vw; - -@@ -1107,22 +952,24 @@ static int ast2600_espi_vw_remove(struct ast2600_espi *espi) - - /* out-of-band channel (CH2) */ - static long ast2600_espi_oob_dma_get_rx(struct file *fp, -- struct ast2600_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { - struct ast2600_espi_oob_dma_rx_desc *d; -- struct ast2600_espi *espi; -+ struct ast2600_espi_oob_dma_rx_desc *rx_descs; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint32_t wptr, pkt_len; -+ u32 wptr, pkt_len; - unsigned long flags; -- uint8_t *pkt; -+ u8 *pkt; - int rc; - -- espi = container_of(oob, struct ast2600_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - wptr = FIELD_PREP(ESPI_OOB_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_OOB_RX_DESC_WPTR)); - -- d = &oob->dma.rxd_virt[wptr]; -+ rx_descs = (struct ast2600_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; -+ d = &rx_descs[wptr]; - - if (!d->dirty) - return -EFAULT; -@@ -1157,7 +1004,7 @@ static long ast2600_espi_oob_dma_get_rx(struct file *fp, - writel(wptr | ESPI_OOB_RX_DESC_WPTR_RECV_EN, espi->regs + ESPI_OOB_RX_DESC_WPTR); - - /* set ready flag base on the next RX descriptor */ -- oob->rx_ready = oob->dma.rxd_virt[wptr].dirty; -+ oob->rx_ready = rx_descs[wptr].dirty; - - spin_unlock_irqrestore(&oob->lock, flags); - -@@ -1170,18 +1017,18 @@ static long ast2600_espi_oob_dma_get_rx(struct file *fp, - } - - static long ast2600_espi_oob_get_rx(struct file *fp, -- struct ast2600_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - -- espi = container_of(oob, struct ast2600_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&oob->rx_mtx)) -@@ -1268,17 +1115,18 @@ static long ast2600_espi_oob_get_rx(struct file *fp, - } - - static long ast2600_espi_oob_dma_put_tx(struct file *fp, -- struct ast2600_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { - struct ast2600_espi_oob_dma_tx_desc *d; -- struct ast2600_espi *espi; -+ struct ast2600_espi_oob_dma_tx_desc *tx_descs; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint32_t rptr, wptr; -- uint8_t *pkt; -+ u32 rptr, wptr; -+ u8 *pkt; - int rc; - -- espi = container_of(oob, struct ast2600_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - pkt = vzalloc(ioc->pkt_len); - if (!pkt) -@@ -1302,7 +1150,8 @@ static long ast2600_espi_oob_dma_put_tx(struct file *fp, - goto free_n_out; - } - -- d = &oob->dma.txd_virt[wptr]; -+ tx_descs = (struct ast2600_espi_oob_dma_tx_desc *)oob->dma.txd_virt; -+ d = &tx_descs[wptr]; - d->cyc = hdr->cyc; - d->tag = hdr->tag; - d->len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -@@ -1324,16 +1173,16 @@ static long ast2600_espi_oob_dma_put_tx(struct file *fp, - } - - static long ast2600_espi_oob_put_tx(struct file *fp, -- struct ast2600_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(oob, struct ast2600_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - if (!mutex_trylock(&oob->tx_mtx)) - return -EAGAIN; -@@ -1397,10 +1246,10 @@ static long ast2600_espi_oob_put_tx(struct file *fp, - - static long ast2600_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2600_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct aspeed_espi_ioc ioc; - -- oob = container_of(fp->private_data, struct ast2600_espi_oob, mdev); -+ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -1423,11 +1272,11 @@ static const struct file_operations ast2600_espi_oob_fops = { - .unlocked_ioctl = ast2600_espi_oob_ioctl, - }; - --static void ast2600_espi_oob_isr(struct ast2600_espi *espi) -+static void ast2600_espi_oob_isr(struct aspeed_espi *espi) - { -- struct ast2600_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - oob = &espi->oob; - -@@ -1444,11 +1293,13 @@ static void ast2600_espi_oob_isr(struct ast2600_espi *espi) - } - } - --static void ast2600_espi_oob_reset(struct ast2600_espi *espi) -+static void ast2600_espi_oob_reset(struct aspeed_espi *espi) - { -- struct ast2600_espi_oob *oob; -+ struct aspeed_espi_oob *oob; -+ struct ast2600_espi_oob_dma_tx_desc *tx_desc; -+ struct ast2600_espi_oob_dma_rx_desc *rx_desc; - dma_addr_t tx_addr, rx_addr; -- uint32_t reg; -+ u32 reg; - int i; - - writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); -@@ -1473,12 +1324,15 @@ static void ast2600_espi_oob_reset(struct ast2600_espi *espi) - tx_addr = oob->dma.tx_addr; - rx_addr = oob->dma.rx_addr; - -+ tx_desc = (struct ast2600_espi_oob_dma_tx_desc *)oob->dma.txd_virt; -+ rx_desc = (struct ast2600_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; -+ - for (i = 0; i < OOB_DMA_DESC_NUM; ++i) { -- oob->dma.txd_virt[i].data_addr = tx_addr; -+ tx_desc[i].data_addr = tx_addr; - tx_addr += PAGE_SIZE; - -- oob->dma.rxd_virt[i].data_addr = rx_addr; -- oob->dma.rxd_virt[i].dirty = 0; -+ rx_desc[i].data_addr = rx_addr; -+ rx_desc[i].dirty = 0; - rx_addr += PAGE_SIZE; - } - -@@ -1507,9 +1361,9 @@ static void ast2600_espi_oob_reset(struct ast2600_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2600_espi_oob_probe(struct ast2600_espi *espi) -+int ast2600_espi_oob_probe(struct aspeed_espi *espi) - { -- struct ast2600_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct device *dev; - int rc; - -@@ -1526,7 +1380,10 @@ static int ast2600_espi_oob_probe(struct ast2600_espi *espi) - - oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); - if (oob->dma.enable) { -- oob->dma.txd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, &oob->dma.txd_addr, GFP_KERNEL); -+ oob->dma.txd_virt = dmam_alloc_coherent(dev, -+ sizeof(struct ast2600_espi_oob_dma_tx_desc) * -+ OOB_DMA_DESC_NUM, -+ &oob->dma.txd_addr, GFP_KERNEL); - if (!oob->dma.txd_virt) { - dev_err(dev, "cannot allocate DMA TX descriptor\n"); - return -ENOMEM; -@@ -1537,7 +1394,10 @@ static int ast2600_espi_oob_probe(struct ast2600_espi *espi) - return -ENOMEM; - } - -- oob->dma.rxd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, &oob->dma.rxd_addr, GFP_KERNEL); -+ oob->dma.rxd_virt = dmam_alloc_coherent(dev, -+ sizeof(struct ast2600_espi_oob_dma_rx_desc) * -+ OOB_DMA_DESC_NUM, -+ &oob->dma.rxd_addr, GFP_KERNEL); - if (!oob->dma.rxd_virt) { - dev_err(dev, "cannot allocate DMA RX descriptor\n"); - return -ENOMEM; -@@ -1565,11 +1425,11 @@ static int ast2600_espi_oob_probe(struct ast2600_espi *espi) - return 0; - } - --static int ast2600_espi_oob_remove(struct ast2600_espi *espi) -+int ast2600_espi_oob_remove(struct aspeed_espi *espi) - { -- struct ast2600_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -1584,11 +1444,16 @@ static int ast2600_espi_oob_remove(struct ast2600_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - - if (oob->dma.enable) { -- dmam_free_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, -+ dmam_free_coherent(dev, -+ sizeof(struct ast2600_espi_oob_dma_tx_desc) * -+ OOB_DMA_DESC_NUM, - oob->dma.txd_virt, oob->dma.txd_addr); - dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, - oob->dma.tx_virt, oob->dma.tx_addr); -- dmam_free_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, -+ -+ dmam_free_coherent(dev, -+ sizeof(struct ast2600_espi_oob_dma_rx_desc) * -+ OOB_DMA_DESC_NUM, - oob->dma.rxd_virt, oob->dma.rxd_addr); - dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, - oob->dma.rx_virt, oob->dma.rx_addr); -@@ -1604,20 +1469,20 @@ static int ast2600_espi_oob_remove(struct ast2600_espi *espi) - - /* flash channel (CH3) */ - static long ast2600_espi_flash_get_rx(struct file *fp, -- struct ast2600_espi_flash *flash, -+ struct aspeed_espi_flash *flash, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - - rc = 0; - -- espi = container_of(flash, struct ast2600_espi, flash); -+ espi = container_of(flash, struct aspeed_espi, flash); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&flash->rx_mtx)) -@@ -1726,16 +1591,16 @@ static long ast2600_espi_flash_get_rx(struct file *fp, - } - - static long ast2600_espi_flash_put_tx(struct file *fp, -- struct ast2600_espi_flash *flash, -+ struct aspeed_espi_flash *flash, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2600_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(flash, struct ast2600_espi, flash); -+ espi = container_of(flash, struct aspeed_espi, flash); - - if (!mutex_trylock(&flash->tx_mtx)) - return -EAGAIN; -@@ -1794,10 +1659,10 @@ static long ast2600_espi_flash_put_tx(struct file *fp, - - static long ast2600_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2600_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct aspeed_espi_ioc ioc; - -- flash = container_of(fp->private_data, struct ast2600_espi_flash, mdev); -+ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -1822,11 +1687,11 @@ static const struct file_operations ast2600_espi_flash_fops = { - .unlocked_ioctl = ast2600_espi_flash_ioctl, - }; - --static void ast2600_espi_flash_isr(struct ast2600_espi *espi) -+static void ast2600_espi_flash_isr(struct aspeed_espi *espi) - { -- struct ast2600_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - flash = &espi->flash; - -@@ -1843,10 +1708,10 @@ static void ast2600_espi_flash_isr(struct ast2600_espi *espi) - } - } - --static void ast2600_espi_flash_reset(struct ast2600_espi *espi) -+static void ast2600_espi_flash_reset(struct aspeed_espi *espi) - { -- struct ast2600_espi_flash *flash; -- uint32_t reg; -+ struct aspeed_espi_flash *flash; -+ u32 reg; - - flash = &espi->flash; - -@@ -1866,14 +1731,14 @@ static void ast2600_espi_flash_reset(struct ast2600_espi *espi) - reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); - writel(reg, espi->regs + ESPI_CTRL); - -- reg = readl(espi->regs + ESPI_CTRL) & ~ESPI_CTRL_FLASH_SAFS_MODE; -- reg |= FIELD_PREP(ESPI_CTRL_FLASH_SAFS_MODE, flash->safs.mode); -+ reg = readl(espi->regs + ESPI_CTRL) & ~ESPI_CTRL_FLASH_EDAF_MODE; -+ reg |= FIELD_PREP(ESPI_CTRL_FLASH_EDAF_MODE, flash->edaf.mode); - writel(reg, espi->regs + ESPI_CTRL); - -- if (flash->safs.mode == SAFS_MODE_MIX) { -- reg = FIELD_PREP(ESPI_FLASH_SAFS_TADDR_BASE, flash->safs.taddr >> 24) -- | FIELD_PREP(ESPI_FLASH_SAFS_TADDR_MASK, (~(flash->safs.size - 1)) >> 24); -- writel(reg, espi->regs + ESPI_FLASH_SAFS_TADDR); -+ if (flash->edaf.mode == EDAF_MODE_MIX) { -+ reg = FIELD_PREP(ESPI_FLASH_EDAF_TADDR_BASE, flash->edaf.taddr >> 24) -+ | FIELD_PREP(ESPI_FLASH_EDAF_TADDR_MASK, (~(flash->edaf.size - 1)) >> 24); -+ writel(reg, espi->regs + ESPI_FLASH_EDAF_TADDR); - } - - if (flash->dma.enable) { -@@ -1892,9 +1757,9 @@ static void ast2600_espi_flash_reset(struct ast2600_espi *espi) - writel(reg, espi->regs + ESPI_CTRL); - } - --static int ast2600_espi_flash_probe(struct ast2600_espi *espi) -+int ast2600_espi_flash_probe(struct aspeed_espi *espi) - { -- struct ast2600_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct device *dev; - int rc; - -@@ -1909,18 +1774,18 @@ static int ast2600_espi_flash_probe(struct ast2600_espi *espi) - mutex_init(&flash->tx_mtx); - mutex_init(&flash->rx_mtx); - -- flash->safs.mode = SAFS_MODE_HW; -+ flash->edaf.mode = EDAF_MODE_HW; - -- of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->safs.mode); -- if (flash->safs.mode == SAFS_MODE_MIX) { -- rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", &flash->safs.taddr); -- if (rc || !IS_ALIGNED(flash->safs.taddr, FLASH_SAFS_ALIGN)) { -+ of_property_read_u32(dev->of_node, "flash-safs-mode", &flash->edaf.mode); -+ if (flash->edaf.mode == EDAF_MODE_MIX) { -+ rc = of_property_read_u32(dev->of_node, "flash-safs-tgt-addr", (u32 *)&flash->edaf.taddr); -+ if (rc || !IS_ALIGNED(flash->edaf.taddr, FLASH_EDAF_ALIGN)) { - dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); - return -ENODEV; - } - -- rc = of_property_read_u32(dev->of_node, "flash-safs-size", &flash->safs.size); -- if (rc || !IS_ALIGNED(flash->safs.size, FLASH_SAFS_ALIGN)) { -+ rc = of_property_read_u32(dev->of_node, "flash-safs-size", (u32 *)&flash->edaf.size); -+ if (rc || !IS_ALIGNED(flash->edaf.size, FLASH_EDAF_ALIGN)) { - dev_err(dev, "cannot get 16MB-aligned SAFS size\n"); - return -ENODEV; - } -@@ -1956,11 +1821,11 @@ static int ast2600_espi_flash_probe(struct ast2600_espi *espi) - return 0; - } - --static int ast2600_espi_flash_remove(struct ast2600_espi *espi) -+int ast2600_espi_flash_remove(struct aspeed_espi *espi) - { -- struct ast2600_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -1988,12 +1853,12 @@ static int ast2600_espi_flash_remove(struct ast2600_espi *espi) - } - - /* global control */ --static irqreturn_t ast2600_espi_isr(int irq, void *arg) -+irqreturn_t ast2600_espi_isr(int irq, void *arg) - { -- struct ast2600_espi *espi; -- uint32_t sts; -+ struct aspeed_espi *espi; -+ u32 sts; - -- espi = (struct ast2600_espi *)arg; -+ espi = (struct aspeed_espi *)arg; - - sts = readl(espi->regs + ESPI_INT_STS); - if (!sts) -@@ -2029,160 +1894,17 @@ static irqreturn_t ast2600_espi_isr(int irq, void *arg) - return IRQ_HANDLED; - } - --static int ast2600_espi_probe(struct platform_device *pdev) -+void ast2600_espi_pre_init(struct aspeed_espi *espi) - { -- struct ast2600_espi *espi; -- struct resource *res; -- struct device *dev; -- int rc; -- -- dev = &pdev->dev; -- -- espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -- if (!espi) -- return -ENOMEM; -- -- espi->dev = dev; -- -- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -- if (rc) { -- dev_err(dev, "cannot set 64-bits DMA mask\n"); -- return rc; -- } -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!res) { -- dev_err(dev, "cannot get resource\n"); -- return -ENODEV; -- } -- -- espi->regs = devm_ioremap_resource(dev, res); -- if (IS_ERR(espi->regs)) { -- dev_err(dev, "cannot map registers\n"); -- return PTR_ERR(espi->regs); -- } -- -- espi->irq = platform_get_irq(pdev, 0); -- if (espi->irq < 0) { -- dev_err(dev, "cannot get IRQ number\n"); -- return -ENODEV; -- } -- -- espi->rst = devm_reset_control_get_exclusive_by_index(dev, 0); -- if (IS_ERR(espi->rst)) { -- dev_err(dev, "cannot get reset control\n"); -- return PTR_ERR(espi->rst); -- } -- -- espi->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(espi->clk)) { -- dev_err(dev, "cannot get clock control\n"); -- return PTR_ERR(espi->clk); -- } -- -- rc = clk_prepare_enable(espi->clk); -- if (rc) { -- dev_err(dev, "cannot enable clocks\n"); -- return rc; -- } -- - writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); -+} - -- rc = ast2600_espi_perif_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); -- return rc; -- } -- -- rc = ast2600_espi_vw_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init vw channel, rc=%d\n", rc); -- goto err_remove_perif; -- } -- -- rc = ast2600_espi_oob_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init oob channel, rc=%d\n", rc); -- goto err_remove_vw; -- } -- -- rc = ast2600_espi_flash_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init flash channel, rc=%d\n", rc); -- goto err_remove_oob; -- } -- -- rc = devm_request_irq(dev, espi->irq, ast2600_espi_isr, 0, dev_name(dev), espi); -- if (rc) { -- dev_err(dev, "cannot request IRQ\n"); -- goto err_remove_flash; -- } -- -+void ast2600_espi_post_init(struct aspeed_espi *espi) -+{ - writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); -- -- platform_set_drvdata(pdev, espi); -- -- dev_info(dev, "module loaded\n"); -- -- return 0; -- --err_remove_flash: -- ast2600_espi_flash_remove(espi); --err_remove_oob: -- ast2600_espi_oob_remove(espi); --err_remove_vw: -- ast2600_espi_vw_remove(espi); --err_remove_perif: -- ast2600_espi_perif_remove(espi); -- -- return rc; - } - --static void ast2600_espi_remove(struct platform_device *pdev) -+void ast2600_espi_deinit(struct aspeed_espi *espi) - { -- struct ast2600_espi *espi; -- struct device *dev; -- int rc; -- -- dev = &pdev->dev; -- -- espi = platform_get_drvdata(pdev); -- - writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); -- -- rc = ast2600_espi_perif_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2600_espi_vw_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2600_espi_oob_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2600_espi_flash_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); - } -- --static const struct of_device_id ast2600_espi_of_matches[] = { -- { .compatible = "aspeed,ast2600-espi" }, -- { }, --}; -- --static struct platform_driver ast2600_espi_driver = { -- .driver = { -- .name = "ast2600-espi", -- .of_match_table = ast2600_espi_of_matches, -- }, -- .probe = ast2600_espi_probe, -- .remove = ast2600_espi_remove, --}; -- --module_platform_driver(ast2600_espi_driver); -- --MODULE_AUTHOR("Chia-Wei Wang "); --MODULE_DESCRIPTION("Control of AST2600 eSPI Device"); --MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2600-espi.h b/drivers/soc/aspeed/espi/ast2600-espi.h -similarity index 91% -rename from drivers/soc/aspeed/ast2600-espi.h -rename to drivers/soc/aspeed/espi/ast2600-espi.h -index eb826f225..56d41a5c7 100644 ---- a/drivers/soc/aspeed/ast2600-espi.h -+++ b/drivers/soc/aspeed/espi/ast2600-espi.h -@@ -1,12 +1,15 @@ - /* SPDX-License-Identifier: GPL-2.0+ */ - /* -+ * Register definitions for Aspeed AST2600 eSPI controller - * Copyright 2023 Aspeed Technology Inc. - */ - #ifndef _AST2600_ESPI_H_ - #define _AST2600_ESPI_H_ - - #include --#include "aspeed-espi-comm.h" -+#include -+ -+#include "aspeed-espi.h" - - /* registers */ - #define ESPI_CTRL 0x000 -@@ -25,7 +28,7 @@ - #define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) - #define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) - #define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) --#define ESPI_CTRL_FLASH_SAFS_MODE GENMASK(11, 10) -+#define ESPI_CTRL_FLASH_EDAF_MODE GENMASK(11, 10) - #define ESPI_CTRL_VW_GPIO_SW BIT(9) - #define ESPI_CTRL_FLASH_SW_RDY BIT(7) - #define ESPI_CTRL_OOB_SW_RDY BIT(4) -@@ -145,9 +148,9 @@ - #define ESPI_PERIF_MMBI_TADDR ESPI_PERIF_MCYC_TADDR - #define ESPI_PERIF_MCYC_MASK 0x08c - #define ESPI_PERIF_MMBI_MASK ESPI_PERIF_MCYC_MASK --#define ESPI_FLASH_SAFS_TADDR 0x090 --#define ESPI_FLASH_SAFS_TADDR_BASE GENMASK(31, 24) --#define ESPI_FLASH_SAFS_TADDR_MASK GENMASK(15, 8) -+#define ESPI_FLASH_EDAF_TADDR 0x090 -+#define ESPI_FLASH_EDAF_TADDR_BASE GENMASK(31, 24) -+#define ESPI_FLASH_EDAF_TADDR_MASK GENMASK(15, 8) - #define ESPI_VW_SYSEVT_INT_EN 0x094 - #define ESPI_VW_SYSEVT 0x098 - #define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) -@@ -273,13 +276,6 @@ - ESPI_INT_STS_FLASH_TX_CMPLT | \ - ESPI_INT_STS_FLASH_RX_CMPLT) - --/* consistent with DTS property "flash-safs-mode" */ --enum ast2600_safs_mode { -- SAFS_MODE_MIX = 0x0, -- SAFS_MODE_SW, -- SAFS_MODE_HW, -- SAFS_MODES, --}; - - /* consistent with DTS property "perif-mmbi-instance-size" */ - enum ast2600_mmbi_instance_size { -@@ -294,4 +290,17 @@ enum ast2600_mmbi_instance_size { - MMBI_INST_SIZE_TYPES, - }; - -+/* function operators */ -+void ast2600_espi_pre_init(struct aspeed_espi *espi); -+void ast2600_espi_post_init(struct aspeed_espi *espi); -+void ast2600_espi_deinit(struct aspeed_espi *espi); -+int ast2600_espi_perif_probe(struct aspeed_espi *espi); -+int ast2600_espi_perif_remove(struct aspeed_espi *espi); -+int ast2600_espi_vw_probe(struct aspeed_espi *espi); -+int ast2600_espi_vw_remove(struct aspeed_espi *espi); -+int ast2600_espi_oob_probe(struct aspeed_espi *espi); -+int ast2600_espi_oob_remove(struct aspeed_espi *espi); -+int ast2600_espi_flash_probe(struct aspeed_espi *espi); -+int ast2600_espi_flash_remove(struct aspeed_espi *espi); -+irqreturn_t ast2600_espi_isr(int irq, void *arg); - #endif -diff --git a/drivers/soc/aspeed/ast2700-espi.c b/drivers/soc/aspeed/espi/ast2700-espi.c -similarity index 76% -rename from drivers/soc/aspeed/ast2700-espi.c -rename to drivers/soc/aspeed/espi/ast2700-espi.c -index c987dc985..f73dec226 100644 ---- a/drivers/soc/aspeed/ast2700-espi.c -+++ b/drivers/soc/aspeed/espi/ast2700-espi.c -@@ -2,6 +2,13 @@ - /* - * Copyright 2023 Aspeed Technology Inc. - */ -+#include "linux/err.h" -+#include "linux/fs.h" -+#include "linux/printk.h" -+#include "linux/spinlock.h" -+#include "linux/stddef.h" -+#include "linux/wait.h" -+#include "linux/wordpart.h" - #include - #include - #include -@@ -24,14 +31,13 @@ - #include - - #include "ast2700-espi.h" -- --#define DEVICE_NAME "aspeed-espi" -+#include "aspeed-espi-comm.h" -+#include "aspeed-espi.h" - - static DEFINE_IDA(ast2700_espi_ida); - - #define PERIF_MCYC_ALIGN SZ_64K - #define PERIF_MMBI_ALIGN SZ_64M --#define PERIF_MMBI_MAX_INST 8 - - #define OOB_DMA_RPTR_KEY 0x4f4f4253 - #define OOB_DMA_DESC_NUM 8 -@@ -39,178 +45,20 @@ static DEFINE_IDA(ast2700_espi_ida); - - #define FLASH_EDAF_ALIGN SZ_16M - --struct ast2700_espi_perif_mmbi { -- void *b2h_virt; -- void *h2b_virt; -- dma_addr_t b2h_addr; -- dma_addr_t h2b_addr; -- struct miscdevice b2h_mdev; -- struct miscdevice h2b_mdev; -- bool host_rwp_update; -- wait_queue_head_t wq; -- struct ast2700_espi_perif *perif; --}; -- --struct ast2700_espi_perif { -- struct { -- bool enable; -- int irq; -- void *virt; -- dma_addr_t taddr; -- uint64_t saddr; -- uint64_t size; -- uint32_t inst_num; -- uint32_t inst_size; -- struct ast2700_espi_perif_mmbi inst[PERIF_MMBI_MAX_INST]; -- } mmbi; -- -- struct { -- bool enable; -- void *virt; -- dma_addr_t taddr; -- uint64_t saddr; -- uint64_t size; -- } mcyc; -- -- struct { -- bool enable; -- void *np_tx_virt; -- dma_addr_t np_tx_addr; -- void *pc_tx_virt; -- dma_addr_t pc_tx_addr; -- void *pc_rx_virt; -- dma_addr_t pc_rx_addr; -- } dma; -- -- bool rtc_enable; -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex np_tx_mtx; -- struct mutex pc_tx_mtx; -- struct mutex pc_rx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2700_espi_vw { -- struct { -- bool hw_mode; -- uint32_t grp; -- uint32_t dir0; -- uint32_t dir1; -- uint32_t val0; -- uint32_t val1; -- } gpio; -- -- struct miscdevice mdev; --}; -- --struct ast2700_espi_oob_dma_tx_desc { -- uint32_t data_addrl; -- uint32_t data_addrh; -- uint8_t cyc; -- uint16_t tag : 4; -- uint16_t len : 12; -- uint8_t msg_type : 3; -- uint8_t raz0 : 1; -- uint8_t pec : 1; -- uint8_t int_en : 1; -- uint8_t pause : 1; -- uint8_t raz1 : 1; -- uint32_t raz2; -- uint32_t raz3; -- uint32_t pad[3]; --} __packed; -- --struct ast2700_espi_oob_dma_rx_desc { -- uint32_t data_addrl; -- uint32_t data_addrh; -- uint8_t cyc; -- uint16_t tag : 4; -- uint16_t len : 12; -- uint8_t raz : 7; -- uint8_t dirty : 1; -- uint32_t pad[1]; --} __packed; -- --struct ast2700_espi_oob { -- struct { -- bool enable; -- struct ast2700_espi_oob_dma_tx_desc *txd_virt; -- dma_addr_t txd_addr; -- struct ast2700_espi_oob_dma_rx_desc *rxd_virt; -- dma_addr_t rxd_addr; -- void *tx_virt; -- dma_addr_t tx_addr; -- void *rx_virt; -- dma_addr_t rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex tx_mtx; -- struct mutex rx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2700_espi_flash { -- struct { -- uint32_t mode; -- phys_addr_t taddr; -- uint64_t size; -- } edaf; -- -- struct { -- bool enable; -- void *tx_virt; -- dma_addr_t tx_addr; -- void *rx_virt; -- dma_addr_t rx_addr; -- } dma; -- -- bool rx_ready; -- wait_queue_head_t wq; -- -- spinlock_t lock; -- struct mutex rx_mtx; -- struct mutex tx_mtx; -- -- struct miscdevice mdev; --}; -- --struct ast2700_espi { -- struct device *dev; -- void __iomem *regs; -- struct clk *clk; -- int dev_id; -- int irq; -- -- struct ast2700_espi_perif perif; -- struct ast2700_espi_vw vw; -- struct ast2700_espi_oob oob; -- struct ast2700_espi_flash flash; --}; -- - /* peripheral channel (CH0) */ - static int ast2700_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2700_espi_perif_mmbi *mmbi; -- struct ast2700_espi_perif *perif; -- struct ast2700_espi *espi; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ struct aspeed_espi *espi; - unsigned long vm_size; - pgprot_t prot; - -- mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, b2h_mdev); -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, b2h_mdev); - - perif = mmbi->perif; - -- espi = container_of(perif, struct ast2700_espi, perif); -- -+ espi = container_of(perif, struct aspeed_espi, perif); - vm_size = vma->vm_end - vma->vm_start; - prot = vma->vm_page_prot; - -@@ -229,17 +77,17 @@ static int ast2700_espi_mmbi_b2h_mmap(struct file *fp, struct vm_area_struct *vm - - static int ast2700_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2700_espi_perif_mmbi *mmbi; -- struct ast2700_espi_perif *perif; -- struct ast2700_espi *espi; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ struct aspeed_espi *espi; - unsigned long vm_size; - pgprot_t prot; - -- mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, h2b_mdev); -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); - - perif = mmbi->perif; - -- espi = container_of(perif, struct ast2700_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - vm_size = vma->vm_end - vma->vm_start; - prot = vma->vm_page_prot; -@@ -259,9 +107,9 @@ static int ast2700_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vm - - static __poll_t ast2700_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) - { -- struct ast2700_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif_mmbi *mmbi; - -- mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, h2b_mdev); -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); - - poll_wait(fp, &mmbi->wq, pt); - -@@ -274,18 +122,18 @@ static __poll_t ast2700_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_st - } - - static long ast2700_espi_perif_pc_get_rx(struct file *fp, -- struct ast2700_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2700_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&perif->pc_rx_mtx)) -@@ -393,16 +241,16 @@ static long ast2700_espi_perif_pc_get_rx(struct file *fp, - } - - static long ast2700_espi_perif_pc_put_tx(struct file *fp, -- struct ast2700_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2700_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (!mutex_trylock(&perif->pc_tx_mtx)) - return -EAGAIN; -@@ -460,16 +308,16 @@ static long ast2700_espi_perif_pc_put_tx(struct file *fp, - } - - static long ast2700_espi_perif_np_put_tx(struct file *fp, -- struct ast2700_espi_perif *perif, -+ struct aspeed_espi_perif *perif, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(perif, struct ast2700_espi, perif); -+ espi = container_of(perif, struct aspeed_espi, perif); - - if (!mutex_trylock(&perif->np_tx_mtx)) - return -EAGAIN; -@@ -528,10 +376,10 @@ static long ast2700_espi_perif_np_put_tx(struct file *fp, - - static long ast2700_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2700_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct aspeed_espi_ioc ioc; - -- perif = container_of(fp->private_data, struct ast2700_espi_perif, mdev); -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -555,11 +403,11 @@ static long ast2700_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned - - static int ast2700_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) - { -- struct ast2700_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - unsigned long vm_size; - pgprot_t vm_prot; - -- perif = container_of(fp->private_data, struct ast2700_espi_perif, mdev); -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); - if (!perif->mcyc.enable) - return -EPERM; - -@@ -598,14 +446,14 @@ static const struct file_operations ast2700_espi_perif_fops = { - - static irqreturn_t ast2700_espi_perif_mmbi_isr(int irq, void *arg) - { -- struct ast2700_espi_perif_mmbi *mmbi; -- struct ast2700_espi_perif *perif; -- struct ast2700_espi *espi; -- uint32_t sts, tmp; -- uint32_t *p; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ struct aspeed_espi *espi; -+ u32 sts, tmp; -+ u32 *p; - int i; - -- espi = (struct ast2700_espi *)arg; -+ espi = (struct aspeed_espi *)arg; - - perif = &espi->perif; - -@@ -619,7 +467,7 @@ static irqreturn_t ast2700_espi_perif_mmbi_isr(int irq, void *arg) - - mmbi = &perif->mmbi.inst[i]; - -- p = (uint32_t *)mmbi->h2b_virt; -+ p = (u32 *)mmbi->h2b_virt; - p[0] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i)); - p[1] = readl(espi->regs + ESPI_MMBI_HOST_RWP(i) + 4); - -@@ -633,11 +481,11 @@ static irqreturn_t ast2700_espi_perif_mmbi_isr(int irq, void *arg) - return IRQ_HANDLED; - } - --static void ast2700_espi_perif_isr(struct ast2700_espi *espi) -+static void ast2700_espi_perif_isr(struct aspeed_espi *espi) - { -- struct ast2700_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - perif = &espi->perif; - -@@ -654,10 +502,10 @@ static void ast2700_espi_perif_isr(struct ast2700_espi *espi) - } - } - --static void ast2700_espi_perif_sw_reset(struct ast2700_espi *espi) -+static void ast2700_espi_perif_sw_reset(struct aspeed_espi *espi) - { - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -681,12 +529,12 @@ static void ast2700_espi_perif_sw_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH0_CTRL); - } - --static void ast2700_espi_perif_reset(struct ast2700_espi *espi) -+static void ast2700_espi_perif_reset(struct aspeed_espi *espi) - { -- struct ast2700_espi_perif *perif; -+ struct aspeed_espi_perif *perif; - struct device *dev; -- uint64_t mask; -- uint32_t reg; -+ u64 mask; -+ u32 reg; - - dev = espi->dev; - -@@ -724,11 +572,11 @@ static void ast2700_espi_perif_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_MMBI_CTRL); - - mask = ~(perif->mmbi.size - 1); -- writel(mask >> 32, espi->regs + ESPI_CH0_MCYC0_MASKH); -+ writel(upper_32_bits(mask), espi->regs + ESPI_CH0_MCYC0_MASKH); - writel(mask & 0xffffffff, espi->regs + ESPI_CH0_MCYC0_MASKL); -- writel((perif->mmbi.saddr >> 32), espi->regs + ESPI_CH0_MCYC0_SADDRH); -+ writel(upper_32_bits(perif->mmbi.saddr), espi->regs + ESPI_CH0_MCYC0_SADDRH); - writel((perif->mmbi.saddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC0_SADDRL); -- writel((perif->mmbi.taddr >> 32), espi->regs + ESPI_CH0_MCYC0_TADDRH); -+ writel(upper_32_bits(perif->mmbi.taddr), espi->regs + ESPI_CH0_MCYC0_TADDRH); - writel((perif->mmbi.taddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC0_TADDRL); - - writel((0x1 << (perif->mmbi.inst_num * 2)) - 1, espi->regs + ESPI_MMBI_INT_EN); -@@ -747,11 +595,11 @@ static void ast2700_espi_perif_reset(struct ast2700_espi *espi) - - if (perif->mcyc.enable) { - mask = ~(perif->mcyc.size - 1); -- writel(mask >> 32, espi->regs + ESPI_CH0_MCYC1_MASKH); -+ writel(upper_32_bits(mask), espi->regs + ESPI_CH0_MCYC1_MASKH); - writel(mask & 0xffffffff, espi->regs + ESPI_CH0_MCYC1_MASKL); -- writel((perif->mcyc.saddr >> 32), espi->regs + ESPI_CH0_MCYC1_SADDRH); -+ writel(upper_32_bits(perif->mcyc.saddr), espi->regs + ESPI_CH0_MCYC1_SADDRH); - writel((perif->mcyc.saddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC1_SADDRL); -- writel((perif->mcyc.taddr >> 32), espi->regs + ESPI_CH0_MCYC1_TADDRH); -+ writel(upper_32_bits(perif->mcyc.taddr), espi->regs + ESPI_CH0_MCYC1_TADDRH); - writel((perif->mcyc.taddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC1_TADDRL); - - reg = readl(espi->regs + ESPI_CH0_MCYC1_MASKL) | ESPI_CH0_MCYC1_MASKL_EN; -@@ -763,11 +611,11 @@ static void ast2700_espi_perif_reset(struct ast2700_espi *espi) - } - - if (perif->dma.enable) { -- writel((perif->dma.np_tx_addr >> 32), espi->regs + ESPI_CH0_NP_TX_DMAH); -+ writel(upper_32_bits(perif->dma.np_tx_addr), espi->regs + ESPI_CH0_NP_TX_DMAH); - writel((perif->dma.np_tx_addr & 0xffffffff), espi->regs + ESPI_CH0_NP_TX_DMAL); -- writel((perif->dma.pc_tx_addr >> 32), espi->regs + ESPI_CH0_PC_TX_DMAH); -+ writel(upper_32_bits(perif->dma.pc_tx_addr), espi->regs + ESPI_CH0_PC_TX_DMAH); - writel((perif->dma.pc_tx_addr & 0xffffffff), espi->regs + ESPI_CH0_PC_TX_DMAL); -- writel((perif->dma.pc_rx_addr >> 32), espi->regs + ESPI_CH0_PC_RX_DMAH); -+ writel(upper_32_bits(perif->dma.pc_rx_addr), espi->regs + ESPI_CH0_PC_RX_DMAH); - writel((perif->dma.pc_rx_addr & 0xffffffff), espi->regs + ESPI_CH0_PC_RX_DMAL); - - reg = readl(espi->regs + ESPI_CH0_CTRL) -@@ -788,15 +636,16 @@ static void ast2700_espi_perif_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH0_CTRL); - } - --static int ast2700_espi_perif_probe(struct ast2700_espi *espi) -+int ast2700_espi_perif_probe(struct aspeed_espi *espi) - { -- struct ast2700_espi_perif_mmbi *mmbi; -- struct ast2700_espi_perif *perif; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; - struct platform_device *pdev; - struct device_node *np; - struct resource res; - struct device *dev; - int i, rc; -+ u64 temp; - - dev = espi->dev; - -@@ -820,16 +669,16 @@ static int ast2700_espi_perif_probe(struct ast2700_espi *espi) - return -ENODEV; - } - -- rc = of_property_read_u64(dev->of_node, "perif-mmbi-src-addr", &perif->mmbi.saddr); -- if (rc || !IS_ALIGNED(perif->mmbi.saddr, PERIF_MMBI_ALIGN)) { -+ rc = of_property_read_u64(dev->of_node, "perif-mmbi-src-addr", &temp); -+ if (rc || !IS_ALIGNED(temp, PERIF_MMBI_ALIGN)) { - dev_err(dev, "cannot get 64MB-aligned MMBI host address\n"); - return -ENODEV; - } -- -+ perif->mmbi.saddr = temp; - rc = of_property_read_u32(dev->of_node, "perif-mmbi-instance-num", &perif->mmbi.inst_num); - if (rc || - perif->mmbi.inst_num == 0 || -- perif->mmbi.inst_num > PERIF_MMBI_MAX_INST || -+ perif->mmbi.inst_num > PERIF_MMBI_INST_NUM || - (perif->mmbi.inst_num & (perif->mmbi.inst_num - 1))) { - dev_err(dev, "cannot get valid MMBI instance number, expect 1/2/4/8\n"); - return -EINVAL; -@@ -859,6 +708,7 @@ static int ast2700_espi_perif_probe(struct ast2700_espi *espi) - } - - memset_io(perif->mmbi.virt, 0, perif->mmbi.size); -+ perif->mmbi.mmbi_isr = ast2700_espi_perif_mmbi_isr; - - for (i = 0; i < perif->mmbi.inst_num; ++i) { - mmbi = &perif->mmbi.inst[i]; -@@ -898,17 +748,19 @@ static int ast2700_espi_perif_probe(struct ast2700_espi *espi) - - perif->mcyc.enable = of_property_read_bool(dev->of_node, "perif-mcyc-enable"); - if (perif->mcyc.enable) { -- rc = of_property_read_u64(dev->of_node, "perif-mcyc-src-addr", &perif->mcyc.saddr); -- if (rc || !IS_ALIGNED(perif->mcyc.saddr, PERIF_MCYC_ALIGN)) { -+ rc = of_property_read_u64(dev->of_node, "perif-mcyc-src-addr", &temp); -+ if (rc || !IS_ALIGNED(temp, PERIF_MCYC_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned memory cycle host address\n"); - return -ENODEV; - } -+ perif->mcyc.saddr = temp; - -- rc = of_property_read_u64(dev->of_node, "perif-mcyc-size", &perif->mcyc.size); -- if (rc || !IS_ALIGNED(perif->mcyc.size, PERIF_MCYC_ALIGN)) { -+ rc = of_property_read_u64(dev->of_node, "perif-mcyc-size", &temp); -+ if (rc || !IS_ALIGNED(temp, PERIF_MCYC_ALIGN)) { - dev_err(dev, "cannot get 64KB-aligned memory cycle size\n"); - return -EINVAL; - } -+ perif->mcyc.size = temp; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (np) { -@@ -965,24 +817,15 @@ static int ast2700_espi_perif_probe(struct ast2700_espi *espi) - - ast2700_espi_perif_reset(espi); - -- if (perif->mmbi.enable) { -- rc = devm_request_irq(dev, espi->perif.mmbi.irq, -- ast2700_espi_perif_mmbi_isr, 0, dev_name(dev), espi); -- if (rc) { -- dev_err(dev, "cannot request MMBI IRQ\n"); -- return rc; -- } -- } -- - return 0; - } - --static int ast2700_espi_perif_remove(struct ast2700_espi *espi) -+int ast2700_espi_perif_remove(struct aspeed_espi *espi) - { -- struct ast2700_espi_perif_mmbi *mmbi; -- struct ast2700_espi_perif *perif; -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; - struct device *dev; -- uint32_t reg; -+ u32 reg; - int i; - - dev = espi->dev; -@@ -1047,13 +890,13 @@ static int ast2700_espi_perif_remove(struct ast2700_espi *espi) - /* virtual wire channel (CH1) */ - static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2700_espi_vw *vw; -- struct ast2700_espi *espi; -- uint32_t gpio0, gpio1; -- uint32_t hw_mode; -+ struct aspeed_espi_vw *vw; -+ struct aspeed_espi *espi; -+ u32 gpio0, gpio1; -+ u32 hw_mode; - -- vw = container_of(fp->private_data, struct ast2700_espi_vw, mdev); -- espi = container_of(vw, struct ast2700_espi, vw); -+ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); -+ espi = container_of(vw, struct aspeed_espi, vw); - gpio0 = vw->gpio.val0; - gpio1 = vw->gpio.val1; - hw_mode = vw->gpio.hw_mode; -@@ -1065,7 +908,7 @@ static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - - switch (cmd) { - case ASPEED_ESPI_VW_GET_GPIO_VAL: -- if (put_user(gpio0, (uint32_t __user *)arg)) { -+ if (put_user(gpio0, (u32 __user *)arg)) { - dev_err(espi->dev, "failed to get vGPIO value0\n"); - return -EFAULT; - } -@@ -1074,7 +917,7 @@ static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - break; - - case ASPEED_ESPI_VW_PUT_GPIO_VAL: -- if (get_user(gpio0, (uint32_t __user *)arg)) { -+ if (get_user(gpio0, (u32 __user *)arg)) { - dev_err(espi->dev, "failed to put vGPIO value0\n"); - return -EFAULT; - } -@@ -1082,9 +925,9 @@ static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - dev_info(espi->dev, "Put vGPIO value0: 0x%x\n", gpio0); - writel(gpio0, espi->regs + ESPI_CH1_GPIO_VAL0); - break; -- -+#ifdef CONFIG_ARM64 - case ASPEED_ESPI_VW_GET_GPIO_VAL1: -- if (put_user(gpio1, (uint32_t __user *)arg)) { -+ if (put_user(gpio1, (u32 __user *)arg)) { - dev_err(espi->dev, "failed to get vGPIO value1\n"); - return -EFAULT; - } -@@ -1093,7 +936,7 @@ static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - break; - - case ASPEED_ESPI_VW_PUT_GPIO_VAL1: -- if (get_user(gpio1, (uint32_t __user *)arg)) { -+ if (get_user(gpio1, (u32 __user *)arg)) { - dev_err(espi->dev, "failed to put vGPIO value1\n"); - return -EFAULT; - } -@@ -1101,7 +944,7 @@ static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned lo - dev_info(espi->dev, "Put vGPIO value1: 0x%x\n", gpio1); - writel(gpio1, espi->regs + ESPI_CH1_GPIO_VAL1); - break; -- -+#endif - default: - return -EINVAL; - }; -@@ -1114,10 +957,103 @@ static const struct file_operations ast2700_espi_vw_fops = { - .unlocked_ioctl = ast2700_espi_vw_ioctl, - }; - --static void ast2700_espi_vw_isr(struct ast2700_espi *espi) -+static inline struct aspeed_espi_vw *to_ast2700_espi_pltrst(struct file *filp) - { -- struct ast2700_espi_vw *vw; -- uint32_t sts; -+ return container_of(filp->private_data, struct aspeed_espi_vw, -+ pltrst_mdev); -+} -+ -+static int ast2700_espi_vw_pltrst_open(struct inode *inode, struct file *filp) -+{ -+ struct aspeed_espi_vw *priv = to_ast2700_espi_pltrst(filp); -+ -+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY) -+ return -EACCES; -+ priv->pltrst.pltrst_avail = true ; /*Setting true returns first data after file open*/ -+ -+ return 0; -+} -+ -+static ssize_t ast2700_espi_vw_pltrst_read(struct file *filp, char __user *buf, -+ size_t count, loff_t *offset) -+{ -+ struct aspeed_espi_vw *vw = to_ast2700_espi_pltrst(filp); -+ DECLARE_WAITQUEUE(wait, current); -+ char data, old_sample; -+ int ret = 0; -+ -+ spin_lock_irq(&vw->pltrst.pltrst_lock); -+ -+ if (filp->f_flags & O_NONBLOCK) { -+ if (!vw->pltrst.pltrst_avail) { -+ ret = -EAGAIN; -+ goto out_unlock; -+ } -+ data = vw->pltrst.pltrst_status; -+ vw->pltrst.pltrst_avail = false; -+ } else { -+ add_wait_queue(&vw->pltrst.pltrst_wq, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ old_sample = vw->pltrst.pltrst_status; -+ -+ do { -+ if (old_sample != vw->pltrst.pltrst_status) { -+ data = vw->pltrst.pltrst_status; -+ vw->pltrst.pltrst_avail = false; -+ break; -+ } -+ -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ } else { -+ spin_unlock_irq(&vw->pltrst.pltrst_lock); -+ schedule(); -+ spin_lock_irq(&vw->pltrst.pltrst_lock); -+ } -+ } while (!ret); -+ -+ remove_wait_queue(&vw->pltrst.pltrst_wq, &wait); -+ set_current_state(TASK_RUNNING); -+ } -+out_unlock: -+ spin_unlock_irq(&vw->pltrst.pltrst_lock); -+ if (ret) -+ return ret; -+ -+ ret = put_user(data, buf); -+ if (!ret) -+ ret = sizeof(data); -+ -+ return ret; -+} -+ -+static unsigned int ast2700_espi_vw_pltrst_poll(struct file *file, -+ poll_table *wait) -+{ -+ struct aspeed_espi_vw *vw = to_ast2700_espi_pltrst(file); -+ unsigned int mask = 0; -+ -+ poll_wait(file, &vw->pltrst.pltrst_wq, wait); -+ if (vw->pltrst.pltrst_avail) -+ mask |= POLLIN; -+ return mask; -+} -+ -+static const struct file_operations ast2700_espi_vw_pltrst_fops = { -+ .owner = THIS_MODULE, -+ .open = ast2700_espi_vw_pltrst_open, -+ .read = ast2700_espi_vw_pltrst_read, -+ .poll = ast2700_espi_vw_pltrst_poll, -+}; -+ -+static void ast2700_espi_vw_isr(struct aspeed_espi *espi) -+{ -+ struct aspeed_espi_vw *vw; -+ u32 sts; -+ u32 sts_evt0; -+ u32 evt0; -+ unsigned long flags; - - vw = &espi->vw; - -@@ -1128,12 +1064,29 @@ static void ast2700_espi_vw_isr(struct ast2700_espi *espi) - vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); - writel(ESPI_CH1_INT_STS_GPIO, espi->regs + ESPI_CH1_INT_STS); - } -+ -+ if (sts & ESPI_CH1_INT_STS_EVT0) { -+ sts_evt0 = readl(espi->regs + ESPI_CH1_EVT0_INT_STS); -+ evt0 = readl(espi->regs + ESPI_CH1_EVT0); -+ if (sts_evt0 & ESPI_CH1_EVT0_INT_STS_PLTRSTN || vw->pltrst.pltrst_status == 'U') { -+ spin_lock_irqsave(&vw->pltrst.pltrst_lock, flags); -+ vw->pltrst.pltrst_status = (evt0 & ESPI_CH1_EVT0_PLTRSTN) ? '1' : '0'; -+ vw->pltrst.pltrst_avail = true; -+ spin_unlock_irqrestore(&vw->pltrst.pltrst_lock, flags); -+ -+ writel(ESPI_CH1_EVT0_INT_STS_PLTRSTN, -+ espi->regs + ESPI_CH1_EVT0_INT_STS); -+ -+ wake_up_interruptible(&vw->pltrst.pltrst_wq); -+ } -+ writel(ESPI_CH1_INT_STS_EVT0, espi->regs + ESPI_CH1_INT_STS); -+ } - } - --static void ast2700_espi_vw_reset(struct ast2700_espi *espi) -+static void ast2700_espi_vw_reset(struct aspeed_espi *espi) - { -- uint32_t reg; -- struct ast2700_espi_vw *vw = &espi->vw; -+ u32 reg; -+ struct aspeed_espi_vw *vw = &espi->vw; - - writel(0x0, espi->regs + ESPI_CH1_INT_EN); - writel(0xffffffff, espi->regs + ESPI_CH1_INT_STS); -@@ -1145,7 +1098,20 @@ static void ast2700_espi_vw_reset(struct ast2700_espi *espi) - vw->gpio.val0 = readl(espi->regs + ESPI_CH1_GPIO_VAL0); - vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); - -- writel(ESPI_CH1_INT_EN_GPIO, espi->regs + ESPI_CH1_INT_EN); -+ if (vw->pltrst.enabled) { -+ spin_lock(&vw->pltrst.pltrst_lock); -+ vw->pltrst.pltrst_status = 'U'; /* Unknown */ -+ vw->pltrst.pltrst_avail = true; -+ spin_unlock(&vw->pltrst.pltrst_lock); -+ -+ writel(ESPI_CH1_EVT0_INT_T2_PLTRSTN, -+ espi->regs + ESPI_CH1_EVT0_INT_T2); -+ writel(ESPI_CH1_EVT0_INT_EN_PLTRSTN, espi->regs + ESPI_CH1_EVT0_INT_EN); -+ writel(ESPI_CH1_INT_EN_GPIO | ESPI_CH1_INT_EN_SYS_EVT0, -+ espi->regs + ESPI_CH1_INT_EN); -+ } else { -+ writel(ESPI_CH1_INT_EN_GPIO, espi->regs + ESPI_CH1_INT_EN); -+ } - - reg = readl(espi->regs + ESPI_CH1_CTRL) - | ((vw->gpio.hw_mode) ? ESPI_CH1_CTRL_GPIO_HW : 0) -@@ -1153,17 +1119,36 @@ static void ast2700_espi_vw_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH1_CTRL); - } - --static int ast2700_espi_vw_probe(struct ast2700_espi *espi) -+int ast2700_espi_vw_probe(struct aspeed_espi *espi) - { - int rc; - struct device *dev = espi->dev; -- struct ast2700_espi_vw *vw = &espi->vw; -+ struct aspeed_espi_vw *vw = &espi->vw; - - vw->gpio.hw_mode = of_property_read_bool(dev->of_node, "vw-gpio-hw-mode"); - of_property_read_u32(dev->of_node, "vw-gpio-group", &vw->gpio.grp); - of_property_read_u32_index(dev->of_node, "vw-gpio-direction", 0, &vw->gpio.dir0); - of_property_read_u32_index(dev->of_node, "vw-gpio-direction", 1, &vw->gpio.dir1); - -+ vw->pltrst.enabled = of_property_read_bool(dev->of_node, "vw-pltrst-monitor"); -+ if (vw->pltrst.enabled) { -+ spin_lock_init(&vw->pltrst.pltrst_lock); -+ init_waitqueue_head(&vw->pltrst.pltrst_wq); -+ vw->pltrst.pltrst_status = 'U'; /* Unknown */ -+ vw->pltrst.pltrst_avail = false; -+ vw->pltrst_mdev.parent = dev; -+ vw->pltrst_mdev.minor = MISC_DYNAMIC_MINOR; -+ vw->pltrst_mdev.name = -+ devm_kasprintf(dev, GFP_KERNEL, "%s-pltrstn%d", -+ DEVICE_NAME, espi->dev_id); -+ vw->pltrst_mdev.fops = &ast2700_espi_vw_pltrst_fops; -+ rc = misc_register(&vw->pltrst_mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", vw->pltrst_mdev.name); -+ return rc; -+ } -+ } -+ - vw->mdev.parent = dev; - vw->mdev.minor = MISC_DYNAMIC_MINOR; - vw->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s-vw%d", DEVICE_NAME, espi->dev_id); -@@ -1179,9 +1164,9 @@ static int ast2700_espi_vw_probe(struct ast2700_espi *espi) - return 0; - } - --static int ast2700_espi_vw_remove(struct ast2700_espi *espi) -+int ast2700_espi_vw_remove(struct aspeed_espi *espi) - { -- struct ast2700_espi_vw *vw; -+ struct aspeed_espi_vw *vw; - - vw = &espi->vw; - -@@ -1194,22 +1179,24 @@ static int ast2700_espi_vw_remove(struct ast2700_espi *espi) - - /* out-of-band channel (CH2) */ - static long ast2700_espi_oob_dma_get_rx(struct file *fp, -- struct ast2700_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { - struct ast2700_espi_oob_dma_rx_desc *d; -- struct ast2700_espi *espi; -+ struct ast2700_espi_oob_dma_rx_desc *rx_descs; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint32_t wptr, pkt_len; -+ u32 wptr, pkt_len; - unsigned long flags; -- uint8_t *pkt; -+ u8 *pkt; - int rc; - -- espi = container_of(oob, struct ast2700_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - wptr = FIELD_PREP(ESPI_CH2_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_CH2_RX_DESC_WPTR)); - -- d = &oob->dma.rxd_virt[wptr]; -+ rx_descs = (struct ast2700_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; -+ d = &rx_descs[wptr]; - - if (!d->dirty) - return -EFAULT; -@@ -1244,7 +1231,7 @@ static long ast2700_espi_oob_dma_get_rx(struct file *fp, - writel(wptr | ESPI_CH2_RX_DESC_WPTR_VALID, espi->regs + ESPI_CH2_RX_DESC_WPTR); - - /* set ready flag base on the next RX descriptor */ -- oob->rx_ready = oob->dma.rxd_virt[wptr].dirty; -+ oob->rx_ready = rx_descs[wptr].dirty; - - spin_unlock_irqrestore(&oob->lock, flags); - -@@ -1257,18 +1244,18 @@ static long ast2700_espi_oob_dma_get_rx(struct file *fp, - } - - static long ast2700_espi_oob_get_rx(struct file *fp, -- struct ast2700_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - -- espi = container_of(oob, struct ast2700_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&oob->rx_mtx)) -@@ -1357,17 +1344,18 @@ static long ast2700_espi_oob_get_rx(struct file *fp, - } - - static long ast2700_espi_oob_dma_put_tx(struct file *fp, -- struct ast2700_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { - struct ast2700_espi_oob_dma_tx_desc *d; -- struct ast2700_espi *espi; -+ struct ast2700_espi_oob_dma_tx_desc *tx_descs; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint32_t rptr, wptr; -- uint8_t *pkt; -+ u32 rptr, wptr; -+ u8 *pkt; - int rc; - -- espi = container_of(oob, struct ast2700_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - pkt = vzalloc(ioc->pkt_len); - if (!pkt) -@@ -1391,7 +1379,8 @@ static long ast2700_espi_oob_dma_put_tx(struct file *fp, - goto free_n_out; - } - -- d = &oob->dma.txd_virt[wptr]; -+ tx_descs = (struct ast2700_espi_oob_dma_tx_desc *)oob->dma.txd_virt; -+ d = &tx_descs[wptr]; - d->cyc = hdr->cyc; - d->tag = hdr->tag; - d->len = (hdr->len_h << 8) | (hdr->len_l & 0xff); -@@ -1413,16 +1402,16 @@ static long ast2700_espi_oob_dma_put_tx(struct file *fp, - } - - static long ast2700_espi_oob_put_tx(struct file *fp, -- struct ast2700_espi_oob *oob, -+ struct aspeed_espi_oob *oob, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(oob, struct ast2700_espi, oob); -+ espi = container_of(oob, struct aspeed_espi, oob); - - if (!mutex_trylock(&oob->tx_mtx)) - return -EAGAIN; -@@ -1486,10 +1475,10 @@ static long ast2700_espi_oob_put_tx(struct file *fp, - - static long ast2700_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2700_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct aspeed_espi_ioc ioc; - -- oob = container_of(fp->private_data, struct ast2700_espi_oob, mdev); -+ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -1512,11 +1501,11 @@ static const struct file_operations ast2700_espi_oob_fops = { - .unlocked_ioctl = ast2700_espi_oob_ioctl, - }; - --static void ast2700_espi_oob_isr(struct ast2700_espi *espi) -+static void ast2700_espi_oob_isr(struct aspeed_espi *espi) - { -- struct ast2700_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - oob = &espi->oob; - -@@ -1533,11 +1522,13 @@ static void ast2700_espi_oob_isr(struct ast2700_espi *espi) - } - } - --static void ast2700_espi_oob_reset(struct ast2700_espi *espi) -+static void ast2700_espi_oob_reset(struct aspeed_espi *espi) - { -- struct ast2700_espi_oob *oob; -+ struct aspeed_espi_oob *oob; -+ struct ast2700_espi_oob_dma_tx_desc *tx_desc; -+ struct ast2700_espi_oob_dma_rx_desc *rx_desc; - dma_addr_t tx_addr, rx_addr; -- uint32_t reg; -+ u32 reg; - int i; - - oob = &espi->oob; -@@ -1562,24 +1553,27 @@ static void ast2700_espi_oob_reset(struct ast2700_espi *espi) - tx_addr = oob->dma.tx_addr; - rx_addr = oob->dma.rx_addr; - -+ tx_desc = (struct ast2700_espi_oob_dma_tx_desc *)oob->dma.txd_virt; -+ rx_desc = (struct ast2700_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; -+ - for (i = 0; i < OOB_DMA_DESC_NUM; ++i) { -- oob->dma.txd_virt[i].data_addrh = tx_addr >> 32; -- oob->dma.txd_virt[i].data_addrl = tx_addr & 0xffffffff; -+ tx_desc[i].data_addrh = upper_32_bits(tx_addr); -+ tx_desc[i].data_addrl = tx_addr & 0xffffffff; - tx_addr += PAGE_SIZE; - -- oob->dma.rxd_virt[i].data_addrh = rx_addr >> 32; -- oob->dma.rxd_virt[i].data_addrl = rx_addr & 0xffffffff; -- oob->dma.rxd_virt[i].dirty = 0; -+ rx_desc[i].data_addrh = upper_32_bits(rx_addr); -+ rx_desc[i].data_addrl = rx_addr & 0xffffffff; -+ rx_desc[i].dirty = 0; - rx_addr += PAGE_SIZE; - } - -- writel(oob->dma.txd_addr >> 32, espi->regs + ESPI_CH2_TX_DMAH); -+ writel(upper_32_bits(oob->dma.txd_addr), espi->regs + ESPI_CH2_TX_DMAH); - writel(oob->dma.txd_addr & 0xffffffff, espi->regs + ESPI_CH2_TX_DMAL); - writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_CH2_TX_DESC_RPTR); - writel(0x0, espi->regs + ESPI_CH2_TX_DESC_WPTR); - writel(OOB_DMA_DESC_NUM, espi->regs + ESPI_CH2_TX_DESC_EPTR); - -- writel(oob->dma.rxd_addr >> 32, espi->regs + ESPI_CH2_RX_DMAH); -+ writel(upper_32_bits(oob->dma.rxd_addr), espi->regs + ESPI_CH2_RX_DMAH); - writel(oob->dma.rxd_addr & 0xffffffff, espi->regs + ESPI_CH2_RX_DMAL); - writel(OOB_DMA_RPTR_KEY, espi->regs + ESPI_CH2_RX_DESC_RPTR); - writel(0x0, espi->regs + ESPI_CH2_RX_DESC_WPTR); -@@ -1601,9 +1595,9 @@ static void ast2700_espi_oob_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH2_CTRL); - } - --static int ast2700_espi_oob_probe(struct ast2700_espi *espi) -+int ast2700_espi_oob_probe(struct aspeed_espi *espi) - { -- struct ast2700_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct device *dev; - int rc; - -@@ -1620,7 +1614,10 @@ static int ast2700_espi_oob_probe(struct ast2700_espi *espi) - - oob->dma.enable = of_property_read_bool(dev->of_node, "oob-dma-mode"); - if (oob->dma.enable) { -- oob->dma.txd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, &oob->dma.txd_addr, GFP_KERNEL); -+ oob->dma.txd_virt = dmam_alloc_coherent(dev, -+ sizeof(struct ast2700_espi_oob_dma_tx_desc) * -+ OOB_DMA_DESC_NUM, -+ &oob->dma.txd_addr, GFP_KERNEL); - if (!oob->dma.txd_virt) { - dev_err(dev, "cannot allocate DMA TX descriptor\n"); - return -ENOMEM; -@@ -1631,7 +1628,10 @@ static int ast2700_espi_oob_probe(struct ast2700_espi *espi) - return -ENOMEM; - } - -- oob->dma.rxd_virt = dmam_alloc_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, &oob->dma.rxd_addr, GFP_KERNEL); -+ oob->dma.rxd_virt = dmam_alloc_coherent(dev, -+ sizeof(struct ast2700_espi_oob_dma_rx_desc) * -+ OOB_DMA_DESC_NUM, -+ &oob->dma.rxd_addr, GFP_KERNEL); - if (!oob->dma.rxd_virt) { - dev_err(dev, "cannot allocate DMA RX descriptor\n"); - return -ENOMEM; -@@ -1659,11 +1659,11 @@ static int ast2700_espi_oob_probe(struct ast2700_espi *espi) - return 0; - } - --static int ast2700_espi_oob_remove(struct ast2700_espi *espi) -+int ast2700_espi_oob_remove(struct aspeed_espi *espi) - { -- struct ast2700_espi_oob *oob; -+ struct aspeed_espi_oob *oob; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -1678,11 +1678,11 @@ static int ast2700_espi_oob_remove(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH2_CTRL); - - if (oob->dma.enable) { -- dmam_free_coherent(dev, sizeof(*oob->dma.txd_virt) * OOB_DMA_DESC_NUM, -+ dmam_free_coherent(dev, sizeof(struct ast2700_espi_oob_dma_tx_desc) * OOB_DMA_DESC_NUM, - oob->dma.txd_virt, oob->dma.txd_addr); - dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, - oob->dma.tx_virt, oob->dma.tx_addr); -- dmam_free_coherent(dev, sizeof(*oob->dma.rxd_virt) * OOB_DMA_DESC_NUM, -+ dmam_free_coherent(dev, sizeof(struct ast2700_espi_oob_dma_rx_desc) * OOB_DMA_DESC_NUM, - oob->dma.rxd_virt, oob->dma.rxd_addr); - dmam_free_coherent(dev, PAGE_SIZE * OOB_DMA_DESC_NUM, - oob->dma.rx_virt, oob->dma.rx_addr); -@@ -1698,20 +1698,20 @@ static int ast2700_espi_oob_remove(struct ast2700_espi *espi) - - /* flash channel (CH3) */ - static long ast2700_espi_flash_get_rx(struct file *fp, -- struct ast2700_espi_flash *flash, -+ struct aspeed_espi_flash *flash, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; - unsigned long flags; -- uint32_t pkt_len; -- uint8_t *pkt; -+ u32 pkt_len; -+ u8 *pkt; - int i, rc; - - rc = 0; - -- espi = container_of(flash, struct ast2700_espi, flash); -+ espi = container_of(flash, struct aspeed_espi, flash); - - if (fp->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&flash->rx_mtx)) -@@ -1820,16 +1820,16 @@ static long ast2700_espi_flash_get_rx(struct file *fp, - } - - static long ast2700_espi_flash_put_tx(struct file *fp, -- struct ast2700_espi_flash *flash, -+ struct aspeed_espi_flash *flash, - struct aspeed_espi_ioc *ioc) - { -- uint32_t reg, cyc, tag, len; -- struct ast2700_espi *espi; -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; - struct espi_comm_hdr *hdr; -- uint8_t *pkt; -+ u8 *pkt; - int i, rc; - -- espi = container_of(flash, struct ast2700_espi, flash); -+ espi = container_of(flash, struct aspeed_espi, flash); - - if (!mutex_trylock(&flash->tx_mtx)) - return -EAGAIN; -@@ -1888,10 +1888,10 @@ static long ast2700_espi_flash_put_tx(struct file *fp, - - static long ast2700_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - { -- struct ast2700_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct aspeed_espi_ioc ioc; - -- flash = container_of(fp->private_data, struct ast2700_espi_flash, mdev); -+ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); - - if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) - return -EFAULT; -@@ -1914,11 +1914,11 @@ static const struct file_operations ast2700_espi_flash_fops = { - .unlocked_ioctl = ast2700_espi_flash_ioctl, - }; - --static void ast2700_espi_flash_isr(struct ast2700_espi *espi) -+static void ast2700_espi_flash_isr(struct aspeed_espi *espi) - { -- struct ast2700_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - unsigned long flags; -- uint32_t sts; -+ u32 sts; - - flash = &espi->flash; - -@@ -1935,11 +1935,11 @@ static void ast2700_espi_flash_isr(struct ast2700_espi *espi) - } - } - --static void ast2700_espi_flash_reset(struct ast2700_espi *espi) -+static void ast2700_espi_flash_reset(struct aspeed_espi *espi) - { -- uint32_t reg; -- uint64_t mask; -- struct ast2700_espi_flash *flash = &espi->flash; -+ u32 reg; -+ u64 mask; -+ struct aspeed_espi_flash *flash = &espi->flash; - - writel(0x0, espi->regs + ESPI_CH3_INT_EN); - writel(0xffffffff, espi->regs + ESPI_CH3_INT_STS); -@@ -1959,9 +1959,9 @@ static void ast2700_espi_flash_reset(struct ast2700_espi *espi) - - if (flash->edaf.mode == EDAF_MODE_MIX) { - mask = ~(flash->edaf.size - 1); -- writel(mask >> 32, espi->regs + ESPI_CH3_EDAF_MASKH); -+ writel(upper_32_bits(mask), espi->regs + ESPI_CH3_EDAF_MASKH); - writel(mask & 0xffffffff, espi->regs + ESPI_CH3_EDAF_MASKL); -- writel(flash->edaf.taddr >> 32, espi->regs + ESPI_CH3_EDAF_TADDRH); -+ writel(upper_32_bits(flash->edaf.taddr), espi->regs + ESPI_CH3_EDAF_TADDRH); - writel(flash->edaf.taddr & 0xffffffff, espi->regs + ESPI_CH3_EDAF_TADDRL); - } - -@@ -1970,9 +1970,9 @@ static void ast2700_espi_flash_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH3_CTRL); - - if (flash->dma.enable) { -- writel(flash->dma.tx_addr >> 32, espi->regs + ESPI_CH3_TX_DMAH); -+ writel(upper_32_bits(flash->dma.tx_addr), espi->regs + ESPI_CH3_TX_DMAH); - writel(flash->dma.tx_addr & 0xffffffff, espi->regs + ESPI_CH3_TX_DMAL); -- writel(flash->dma.rx_addr >> 32, espi->regs + ESPI_CH3_RX_DMAH); -+ writel(upper_32_bits(flash->dma.rx_addr), espi->regs + ESPI_CH3_RX_DMAH); - writel(flash->dma.rx_addr & 0xffffffff, espi->regs + ESPI_CH3_RX_DMAL); - - reg = readl(espi->regs + ESPI_CH3_CTRL) -@@ -1987,9 +1987,9 @@ static void ast2700_espi_flash_reset(struct ast2700_espi *espi) - writel(reg, espi->regs + ESPI_CH3_CTRL); - } - --static int ast2700_espi_flash_probe(struct ast2700_espi *espi) -+int ast2700_espi_flash_probe(struct aspeed_espi *espi) - { -- struct ast2700_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct device_node *np; - struct resource res; - struct device *dev; -@@ -2022,8 +2022,6 @@ static int ast2700_espi_flash_probe(struct ast2700_espi *espi) - - flash->edaf.taddr = res.start; - flash->edaf.size = resource_size(&res); -- dev_info(dev, "eDAF address: 0x%llx\n", flash->edaf.taddr); -- dev_info(dev, "eDAF size: 0x%llx\n", flash->edaf.size); - - virt = devm_ioremap_resource(dev, &res); - if (!virt) { -@@ -2062,11 +2060,11 @@ static int ast2700_espi_flash_probe(struct ast2700_espi *espi) - return 0; - } - --static int ast2700_espi_flash_remove(struct ast2700_espi *espi) -+int ast2700_espi_flash_remove(struct aspeed_espi *espi) - { -- struct ast2700_espi_flash *flash; -+ struct aspeed_espi_flash *flash; - struct device *dev; -- uint32_t reg; -+ u32 reg; - - dev = espi->dev; - -@@ -2094,10 +2092,10 @@ static int ast2700_espi_flash_remove(struct ast2700_espi *espi) - } - - /* global control */ --static irqreturn_t ast2700_espi_isr(int irq, void *arg) -+irqreturn_t ast2700_espi_isr(int irq, void *arg) - { -- uint32_t sts; -- struct ast2700_espi *espi = (struct ast2700_espi *)arg; -+ u32 sts; -+ struct aspeed_espi *espi = (struct aspeed_espi *)arg; - - sts = readl(espi->regs + ESPI_INT_STS); - if (!sts) -@@ -2127,178 +2125,56 @@ static irqreturn_t ast2700_espi_isr(int irq, void *arg) - return IRQ_HANDLED; - } - --static int ast2700_espi_probe(struct platform_device *pdev) -+void ast2700_espi_pre_init(struct aspeed_espi *espi) - { -- struct ast2700_espi *espi; -- struct resource *res; - struct device *dev; - struct regmap *scu1; -- uint32_t reg; -+ u32 reg; - int rc; - -- dev = &pdev->dev; -- -- espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -- if (!espi) -- return -ENOMEM; -- -- espi->dev = dev; -- -- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -- if (rc) { -- dev_err(dev, "cannot set 64-bits DMA mask\n"); -- return rc; -- } -+ dev = espi->dev; - - scu1 = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(scu1)) { -- dev_err(dev, "failed to find SCU1 regmap\n"); -- return PTR_ERR(scu1); -+ dev_err(dev, "failed to find SCU1 regmap, error %ld\n", PTR_ERR(scu1)); -+ return; - } - rc = regmap_update_bits(scu1, SCU1_DDR, - SCU1_DDR_DIS_ESPI0_AHB | SCU1_DDR_DIS_ESPI1_AHB, - 0); -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!res) { -- dev_err(dev, "cannot get resource\n"); -- return -ENODEV; -- } -- -- espi->regs = devm_ioremap_resource(dev, res); -- if (IS_ERR(espi->regs)) { -- dev_err(dev, "cannot map registers\n"); -- return PTR_ERR(espi->regs); -- } -- -- espi->irq = platform_get_irq(pdev, 0); -- if (espi->irq < 0) { -- dev_err(dev, "cannot get IRQ number\n"); -- return -ENODEV; -- } -- -- espi->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(espi->clk)) { -- dev_err(dev, "cannot get clock control\n"); -- return PTR_ERR(espi->clk); -- } -- -- rc = clk_prepare_enable(espi->clk); -- if (rc) { -- dev_err(dev, "cannot enable clocks\n"); -- return rc; -+ if (!rc) { -+ dev_err(dev, "failed to update SCU1 regmap, error %d\n", rc); -+ return; - } - - espi->dev_id = ida_alloc(&ast2700_espi_ida, GFP_KERNEL); - if (espi->dev_id < 0) { -- dev_err(dev, "cannote allocate device ID\n"); -- return espi->dev_id; -+ dev_err(dev, "cannote allocate device ID, error %d\n", espi->dev_id); -+ return; - } - - reg = readl(espi->regs + ESPI_INT_EN); - reg &= ~ESPI_INT_EN_RST_DEASSERT; - writel(reg, espi->regs + ESPI_INT_EN); -+} - -- rc = ast2700_espi_perif_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init CH0, rc=%d\n", rc); -- return rc; -- } -- -- rc = ast2700_espi_vw_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init CH1, rc=%d\n", rc); -- goto err_remove_perif; -- } -- -- rc = ast2700_espi_oob_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init CH2, rc=%d\n", rc); -- goto err_remove_vw; -- } -- -- rc = ast2700_espi_flash_probe(espi); -- if (rc) { -- dev_err(dev, "cannot init CH3, rc=%d\n", rc); -- goto err_remove_oob; -- } -- -- rc = devm_request_irq(dev, espi->irq, ast2700_espi_isr, 0, dev_name(dev), espi); -- if (rc) { -- dev_err(dev, "cannot request IRQ\n"); -- goto err_remove_flash; -- } -+void ast2700_espi_post_init(struct aspeed_espi *espi) -+{ -+ u32 reg; - - reg = readl(espi->regs + ESPI_INT_EN); - reg |= ESPI_INT_EN_RST_DEASSERT; - writel(reg, espi->regs + ESPI_INT_EN); -- -- platform_set_drvdata(pdev, espi); -- -- dev_info(dev, "module loaded\n"); -- -- return 0; -- --err_remove_flash: -- ast2700_espi_flash_remove(espi); --err_remove_oob: -- ast2700_espi_oob_remove(espi); --err_remove_vw: -- ast2700_espi_vw_remove(espi); --err_remove_perif: -- ast2700_espi_perif_remove(espi); -- -- return rc; - } - --static void ast2700_espi_remove(struct platform_device *pdev) -+void ast2700_espi_deinit(struct aspeed_espi *espi) - { -- struct ast2700_espi *espi; - struct device *dev; -- uint32_t reg; -- int rc; -- -- dev = &pdev->dev; -+ u32 reg; - -- espi = platform_get_drvdata(pdev); -+ dev = espi->dev; - - reg = readl(espi->regs + ESPI_INT_EN); - reg &= ~ESPI_INT_EN_RST_DEASSERT; - writel(reg, espi->regs + ESPI_INT_EN); -- -- rc = ast2700_espi_perif_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2700_espi_vw_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2700_espi_oob_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); -- -- rc = ast2700_espi_flash_remove(espi); -- if (rc) -- dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); - } -- --static const struct of_device_id ast2700_espi_of_matches[] = { -- { .compatible = "aspeed,ast2700-espi" }, -- { }, --}; -- --static struct platform_driver ast2700_espi_driver = { -- .driver = { -- .name = "ast2700-espi", -- .of_match_table = ast2700_espi_of_matches, -- }, -- .probe = ast2700_espi_probe, -- .remove = ast2700_espi_remove, --}; -- --module_platform_driver(ast2700_espi_driver); -- --MODULE_AUTHOR("Chia-Wei Wang "); --MODULE_DESCRIPTION("Control of AST2700 eSPI Device"); --MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/aspeed/ast2700-espi.h b/drivers/soc/aspeed/espi/ast2700-espi.h -similarity index 89% -rename from drivers/soc/aspeed/ast2700-espi.h -rename to drivers/soc/aspeed/espi/ast2700-espi.h -index 6b2900496..fbf3e2cf2 100644 ---- a/drivers/soc/aspeed/ast2700-espi.h -+++ b/drivers/soc/aspeed/espi/ast2700-espi.h -@@ -1,12 +1,13 @@ - /* SPDX-License-Identifier: GPL-2.0+ */ - /* -+ * Register definitions for Aspeed AST2700 eSPI controller - * Copyright 2023 Aspeed Technology Inc. - */ - #ifndef _AST2700_ESPI_H_ - #define _AST2700_ESPI_H_ - - #include --#include "aspeed-espi-comm.h" -+#include "aspeed-espi.h" - - /* SCU regiseters */ - #define SCU1_DDR 0x0c8 -@@ -113,14 +114,22 @@ - #define ESPI_CH1_STS 0x204 - #define ESPI_CH1_INT_STS 0x208 - #define ESPI_CH1_INT_STS_GPIO BIT(2) -+#define ESPI_CH1_INT_STS_EVT0 BIT(0) - #define ESPI_CH1_INT_EN 0x20c - #define ESPI_CH1_INT_EN_GPIO BIT(2) -+#define ESPI_CH1_INT_EN_SYS_EVT0 BIT(0) - #define ESPI_CH1_EVT0 0x210 -+#define ESPI_CH1_EVT0_PLTRSTN BIT(5) - #define ESPI_CH1_EVT0_INT_EN 0x214 -+#define ESPI_CH1_EVT0_INT_EN_PLTRSTN BIT(5) - #define ESPI_CH1_EVT0_INT_T0 0x218 -+#define ESPI_CH1_EVT0_INT_T0_PLTRSTN BIT(5) - #define ESPI_CH1_EVT0_INT_T1 0x21c -+#define ESPI_CH1_EVT0_INT_T1_PLTRSTN BIT(5) - #define ESPI_CH1_EVT0_INT_T2 0x220 -+#define ESPI_CH1_EVT0_INT_T2_PLTRSTN BIT(5) - #define ESPI_CH1_EVT0_INT_STS 0x224 -+#define ESPI_CH1_EVT0_INT_STS_PLTRSTN BIT(5) - #define ESPI_CH1_EVT1 0x230 - #define ESPI_CH1_EVT1_INT_EN 0x234 - #define ESPI_CH1_EVT1_INT_T0 0x238 -@@ -271,11 +280,17 @@ - #define ESPI_MMBI_INT_EN 0x80c - #define ESPI_MMBI_HOST_RWP(x) (0x810 + ((x) << 3)) - --enum ast2700_edaf_mode { -- EDAF_MODE_MIX, -- EDAF_MODE_SW, -- EDAF_MODE_HW, -- EDAF_MODES, --}; -+void ast2700_espi_pre_init(struct aspeed_espi *espi); -+void ast2700_espi_post_init(struct aspeed_espi *espi); -+void ast2700_espi_deinit(struct aspeed_espi *espi); -+int ast2700_espi_perif_probe(struct aspeed_espi *espi); -+int ast2700_espi_perif_remove(struct aspeed_espi *espi); -+int ast2700_espi_vw_probe(struct aspeed_espi *espi); -+int ast2700_espi_vw_remove(struct aspeed_espi *espi); -+int ast2700_espi_oob_probe(struct aspeed_espi *espi); -+int ast2700_espi_oob_remove(struct aspeed_espi *espi); -+int ast2700_espi_flash_probe(struct aspeed_espi *espi); -+int ast2700_espi_flash_remove(struct aspeed_espi *espi); -+irqreturn_t ast2700_espi_isr(int irq, void *arg); - - #endif -diff --git a/drivers/soc/aspeed/ast2700-rtc-over-espi.c b/drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c -similarity index 100% -rename from drivers/soc/aspeed/ast2700-rtc-over-espi.c -rename to drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c -diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/video_main.c -index 295c4f2fb..547a7a252 100644 ---- a/drivers/soc/aspeed/rvas/video_main.c -+++ b/drivers/soc/aspeed/rvas/video_main.c -@@ -1150,10 +1150,16 @@ void enable_rvas_engines(struct AstRVAS *pAstRVAS) - - static void reset_rvas_engine(struct AstRVAS *pAstRVAS) - { -- disable_rvas_engines(pAstRVAS); -- if (pAstRVAS->config->version == 7) -- reset_control_deassert(pAstRVAS->rvas_reset); -- enable_rvas_engines(pAstRVAS); -+ if (pAstRVAS->config->version == 7) { -+ regmap_write(pAstRVAS->scu, 0x200, 0x200); -+ mdelay(200); -+ regmap_write(pAstRVAS->scu, 0x244, 0x2000000); -+ mdelay(100); -+ regmap_write(pAstRVAS->scu, 0x204, 0x200); -+ } else { -+ disable_rvas_engines(pAstRVAS); -+ enable_rvas_engines(pAstRVAS); -+ } - rvas_init(pAstRVAS); - } - -diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c -index c93986815..02fd6afe4 100644 ---- a/drivers/tty/serial/8250/8250_aspeed.c -+++ b/drivers/tty/serial/8250/8250_aspeed.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -40,7 +41,6 @@ - #define VUART_GCRG 0x38 - #define VUART_GCRG_CHARACTER_TIMEOUT_TIME_CONTROL BIT(1) - --#define DMA_TX_BUFSZ PAGE_SIZE - #define DMA_RX_BUFSZ (64 * 1024) - - struct uart_ops ast8250_pops; -@@ -55,14 +55,14 @@ struct ast8250_vuart { - struct ast8250_udma { - u32 ch; - -- u32 tx_fifosz; -- u32 rx_fifosz; -+ u32 tx_rbsz; -+ u32 rx_rbsz; - - dma_addr_t tx_addr; - dma_addr_t rx_addr; - -- struct kfifo *tx_fifo; -- struct kfifo *rx_fifo; -+ struct tty_port *tport; -+ struct circ_buf *rx_rb; - - bool tx_tmout_dis; - bool rx_tmout_dis; -@@ -71,6 +71,7 @@ struct ast8250_udma { - struct ast8250_data { - int line; - -+ struct resource *res; - u8 __iomem *regs; - - bool is_vuart; -@@ -83,62 +84,76 @@ struct ast8250_data { - struct ast8250_udma dma; - }; - --static void ast8250_dma_tx_complete(int tx_fifo_rptr, void *id) -+static void ast8250_dma_tx_complete(int tx_rb_rptr, void *id) - { -- unsigned long flags; -- struct uart_port *port = (struct uart_port*)id; -+ unsigned long flags; -+ struct uart_port *port = id; - struct ast8250_data *data = port->private_data; -- struct kfifo *tx_fifo = data->dma.tx_fifo; -- unsigned int len; -+ unsigned int count, tail; - -- spin_lock_irqsave(&port->lock, flags); -+ uart_port_lock_irqsave(port, &flags); - -- len = kfifo_out(tx_fifo, NULL, tx_fifo_rptr); -- port->icount.tx += len; -+ count = kfifo_out_linear(&data->dma.tport->xmit_fifo, &tail, data->dma.tx_rbsz); -+ count = CIRC_CNT(tx_rb_rptr, tail, data->dma.tx_rbsz); -+ if (!count) -+ count = data->dma.tx_rbsz; -+ kfifo_dma_out_finish(&data->dma.tport->xmit_fifo, count); -+ port->icount.tx += count; - -- if (kfifo_len(tx_fifo) < WAKEUP_CHARS) -+ if (kfifo_len(&data->dma.tport->xmit_fifo) < WAKEUP_CHARS) - uart_write_wakeup(port); - -- spin_unlock_irqrestore(&port->lock, flags); -+ uart_port_unlock_irqrestore(port, flags); - } - --static void ast8250_dma_rx_complete(int rx_fifo_wptr, void *id) -+static void ast8250_dma_rx_complete(int rx_rb_wptr, void *id) - { - unsigned long flags; - struct uart_port *up = (struct uart_port*)id; - struct tty_port *tp = &up->state->port; - struct ast8250_data *data = up->private_data; - struct ast8250_udma *dma = &data->dma; -- struct kfifo *rx_fifo = dma->rx_fifo; -- u32 len = 0; -- u8 buf[128]; -+ struct circ_buf *rx_rb = dma->rx_rb; -+ u32 rx_rbsz = dma->rx_rbsz; -+ u32 count = 0; -+ -+ uart_port_lock_irqsave(up, &flags); - -- spin_lock_irqsave(&up->lock, flags); -+ rx_rb->head = rx_rb_wptr; - - dma_sync_single_for_cpu(up->dev, -- dma->rx_addr, dma->rx_fifosz, DMA_FROM_DEVICE); -+ dma->rx_addr, dma->rx_rbsz, DMA_FROM_DEVICE); -+ -+ while (CIRC_CNT(rx_rb->head, rx_rb->tail, rx_rbsz)) { -+ count = CIRC_CNT_TO_END(rx_rb->head, rx_rb->tail, rx_rbsz); -+ -+ tty_insert_flip_string(tp, rx_rb->buf + rx_rb->tail, count); -+ -+ rx_rb->tail += count; -+ rx_rb->tail %= rx_rbsz; - -- while (!kfifo_is_empty(rx_fifo)) { -- len = kfifo_out(rx_fifo, buf, sizeof(buf)); -- tty_insert_flip_string(tp, buf, len); -- up->icount.rx += len; -+ up->icount.rx += count; - } - -- tty_flip_buffer_push(tp); -+ if (count) { -+ aspeed_udma_set_rx_rptr(data->dma.ch, rx_rb->tail); -+ tty_flip_buffer_push(tp); -+ } - -- spin_unlock_irqrestore(&up->lock, flags); -+ uart_port_unlock_irqrestore(up, flags); - } - - static void ast8250_dma_start_tx(struct uart_port *port) - { - struct ast8250_data *data = port->private_data; - struct ast8250_udma *dma = &data->dma; -- struct kfifo *tx_fifo = dma->tx_fifo; -+ typeof(&dma->tport->xmit_fifo) tmp = &dma->tport->xmit_fifo; -+ struct __kfifo *tx_rb = &tmp->kfifo; - - dma_sync_single_for_device(port->dev, -- dma->tx_addr, dma->tx_fifosz, DMA_TO_DEVICE); -+ dma->tx_addr, dma->tx_rbsz, DMA_TO_DEVICE); - -- aspeed_udma_set_tx_wptr(dma->ch, kfifo_len(tx_fifo)); -+ aspeed_udma_set_tx_wptr(dma->ch, tx_rb->in); - } - - static void ast8250_dma_pops_hook(struct uart_port *port) -@@ -232,49 +247,53 @@ static int ast8250_startup(struct uart_port *port) - if (data->use_dma) { - dma = &data->dma; - -- dma->tx_fifosz = DMA_TX_BUFSZ; -- dma->rx_fifosz = DMA_RX_BUFSZ; -+ dma->tx_rbsz = UART_XMIT_SIZE; -+ dma->rx_rbsz = DMA_RX_BUFSZ; - -- if (kfifo_alloc(dma->tx_fifo, dma->tx_fifosz, GFP_KERNEL)) { -- dev_err(port->dev, "failed to allocate TX DMA ring buffer\n"); -+ /* -+ * We take the xmit buffer passed from upper layers as -+ * the DMA TX buffer and allocate a new buffer for the -+ * RX use. -+ * -+ * To keep the TX/RX operation consistency, we use the -+ * streaming DMA interface instead of the coherent one -+ */ -+ dma->tport = &port->state->port; -+ dma->rx_rb->buf = kzalloc(data->dma.rx_rbsz, GFP_KERNEL); -+ if (IS_ERR_OR_NULL(dma->rx_rb->buf)) { -+ dev_err(port->dev, "failed to allcoate RX DMA buffer\n"); - rc = -ENOMEM; - goto out; - } - -- if (kfifo_alloc(dma->rx_fifo, dma->rx_fifosz, GFP_KERNEL)) { -- dev_err(port->dev, "failed to allocate RX DMA ring buffer\n"); -- rc = -ENOMEM; -- goto free_tx_fifo; -- } -- -- dma->tx_addr = dma_map_single(port->dev, dma->tx_fifo->kfifo.data, -- dma->tx_fifosz, DMA_TO_DEVICE); -+ dma->tx_addr = dma_map_single(port->dev, dma->tport->xmit_buf, -+ dma->tx_rbsz, DMA_TO_DEVICE); - if (dma_mapping_error(port->dev, dma->tx_addr)) { - dev_err(port->dev, "failed to map streaming TX DMA region\n"); - rc = -ENOMEM; -- goto free_rx_fifo; -+ goto free_dma_n_out; - } - -- dma->rx_addr = dma_map_single(port->dev, dma->rx_fifo->kfifo.data, -- dma->rx_fifosz, DMA_FROM_DEVICE); -+ dma->rx_addr = dma_map_single(port->dev, dma->rx_rb->buf, -+ dma->rx_rbsz, DMA_FROM_DEVICE); - if (dma_mapping_error(port->dev, dma->rx_addr)) { - dev_err(port->dev, "failed to map streaming RX DMA region\n"); - rc = -ENOMEM; -- goto free_rx_fifo; -+ goto free_dma_n_out; - } - - rc = aspeed_udma_request_tx_chan(dma->ch, dma->tx_addr, -- dma->tx_fifo, dma->tx_fifosz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis); -+ dma->tx_rbsz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis); - if (rc) { - dev_err(port->dev, "failed to request DMA TX channel\n"); -- goto free_rx_fifo; -+ goto free_dma_n_out; - } - - rc = aspeed_udma_request_rx_chan(dma->ch, dma->rx_addr, -- dma->rx_fifo, dma->rx_fifosz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis); -+ dma->rx_rbsz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis); - if (rc) { - dev_err(port->dev, "failed to request DMA RX channel\n"); -- goto free_rx_fifo; -+ goto free_dma_n_out; - } - - ast8250_dma_pops_hook(port); -@@ -286,12 +305,8 @@ static int ast8250_startup(struct uart_port *port) - memset(&port->icount, 0, sizeof(port->icount)); - return serial8250_do_startup(port); - --free_rx_fifo: -- kfifo_free(dma->rx_fifo); -- --free_tx_fifo: -- kfifo_free(dma->tx_fifo); -- -+free_dma_n_out: -+ kfree(dma->rx_rb->buf); - out: - return rc; - } -@@ -320,12 +335,12 @@ static void ast8250_shutdown(struct uart_port *port) - dev_err(port->dev, "failed to free DMA TX channel, rc=%d\n", rc); - - dma_unmap_single(port->dev, dma->tx_addr, -- dma->tx_fifosz, DMA_TO_DEVICE); -+ dma->tx_rbsz, DMA_TO_DEVICE); - dma_unmap_single(port->dev, dma->rx_addr, -- dma->rx_fifosz, DMA_FROM_DEVICE); -+ dma->rx_rbsz, DMA_FROM_DEVICE); - -- kfree(dma->tx_fifo); -- kfree(dma->rx_fifo); -+ if (dma->rx_rb->buf) -+ kfree(dma->rx_rb->buf); - } - - if (data->is_vuart) -@@ -348,46 +363,19 @@ static int __maybe_unused ast8250_resume(struct device *dev) - return 0; - } - --static int ast8250_probe(struct platform_device *pdev) -+static int ast8250_probe_of(struct platform_device *pdev, struct uart_port *p, -+ struct ast8250_data *data) - { -- int rc; -- struct uart_8250_port uart = {}; -- struct uart_port *port = &uart.port; - struct device *dev = &pdev->dev; -- struct ast8250_data *data; -- uint32_t plat = (unsigned long)of_device_get_match_data(dev); -- -- struct resource *res; -- u32 irq; -- -- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -- if (rc) { -- dev_err(dev, "cannot set 64-bits DMA mask\n"); -- return rc; -- } -- -- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -- if (data == NULL) -- return -ENOMEM; -- -- data->dma.rx_fifo = devm_kzalloc(dev, sizeof(data->dma.rx_fifo), GFP_KERNEL); -- if (!data->dma.rx_fifo) -- return -ENOMEM; -- -- irq = platform_get_irq(pdev, 0); -- if (irq < 0) { -- if (irq != -EPROBE_DEFER) -- dev_err(dev, "failed to get IRQ number\n"); -- return irq; -- } -+ int rc; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (res == NULL) { -+ data->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!data->res) { - dev_err(dev, "failed to get register base\n"); - return -ENODEV; - } - -- data->regs = devm_ioremap(dev, res->start, resource_size(res)); -+ data->regs = devm_ioremap(dev, data->res->start, resource_size(data->res)); - if (IS_ERR(data->regs)) { - dev_err(dev, "failed to map registers\n"); - return PTR_ERR(data->regs); -@@ -399,18 +387,12 @@ static int ast8250_probe(struct platform_device *pdev) - return -ENODEV; - } - -- rc = clk_prepare_enable(data->clk); -- if (rc) { -- dev_err(dev, "failed to enable clock\n"); -- return rc; -- } -- - data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); -- if (!IS_ERR(data->rst)) -- reset_control_deassert(data->rst); - - data->is_vuart = of_property_read_bool(dev->of_node, "virtual"); - if (data->is_vuart) { -+ u32 plat = (unsigned long)of_device_get_match_data(dev); -+ - rc = of_property_read_u32(dev->of_node, "port", &data->vuart.port); - if (rc) { - dev_err(dev, "failed to get VUART port address\n"); -@@ -433,17 +415,10 @@ static int ast8250_probe(struct platform_device *pdev) - data->vuart.character_timeout_time_en = true; - else - data->vuart.character_timeout_time_en = false; -- -- ast8250_vuart_init(data); -- ast8250_vuart_set_host_tx_discard(data, true); -- ast8250_vuart_set_enable(data, true); - } - - data->use_dma = of_property_read_bool(dev->of_node, "dma-mode"); - if (data->use_dma) { -- dev_warn(dev, "DMA mode not ready\n"); -- data->use_dma = false; -- /* - rc = of_property_read_u32(dev->of_node, "dma-channel", &data->dma.ch); - if (rc) { - dev_err(dev, "failed to get DMA channel\n"); -@@ -452,27 +427,73 @@ static int ast8250_probe(struct platform_device *pdev) - - data->dma.tx_tmout_dis = of_property_read_bool(dev->of_node, "dma-tx-timeout-disable"); - data->dma.rx_tmout_dis = of_property_read_bool(dev->of_node, "dma-rx-timeout-disable"); -- */ -+ } -+ -+ return 0; -+} -+ -+static int ast8250_probe(struct platform_device *pdev) -+{ -+ int rc; -+ struct uart_8250_port uart = {}; -+ struct uart_port *port = &uart.port; -+ struct device *dev = &pdev->dev; -+ struct ast8250_data *data; -+ -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; -+ } -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->dma.rx_rb = devm_kzalloc(dev, sizeof(data->dma.rx_rb), GFP_KERNEL); -+ if (!data->dma.rx_rb) -+ return -ENOMEM; -+ -+ rc = ast8250_probe_of(pdev, port, data); -+ if (rc) -+ return rc; -+ -+ rc = clk_prepare_enable(data->clk); -+ if (rc) { -+ dev_err(dev, "failed to enable clock\n"); -+ return rc; -+ } -+ -+ if (!IS_ERR(data->rst)) -+ reset_control_deassert(data->rst); -+ -+ if (data->is_vuart) { -+ ast8250_vuart_init(data); -+ ast8250_vuart_set_host_tx_discard(data, true); -+ ast8250_vuart_set_enable(data, true); - } - - spin_lock_init(&port->lock); - port->dev = dev; -- port->type = PORT_16550A; -- port->irq = irq; -- port->line = of_alias_get_id(dev->of_node, "serial"); -- port->handle_irq = ast8250_handle_irq; -- port->mapbase = res->start; -- port->mapsize = resource_size(res); -+ port->mapbase = data->res->start; -+ port->mapsize = resource_size(data->res); - port->membase = data->regs; -- port->uartclk = clk_get_rate(data->clk); -- port->regshift = 2; -- port->iotype = UPIO_MEM32; - port->flags = UPF_FIXED_TYPE | UPF_FIXED_PORT | UPF_SHARE_IRQ; - port->startup = ast8250_startup; - port->shutdown = ast8250_shutdown; - port->private_data = data; - uart.bugs |= UART_BUG_TXRACE; - -+ rc = uart_read_port_properties(port); -+ if (rc) -+ return rc; -+ -+ port->type = (data->is_vuart) ? PORT_ASPEED_VUART : PORT_16550A; -+ port->handle_irq = ast8250_handle_irq; -+ port->uartclk = clk_get_rate(data->clk); -+ -+ uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE; -+ - data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) { - dev_err(dev, "failed to register 8250 port\n"); -@@ -488,12 +509,12 @@ static int ast8250_probe(struct platform_device *pdev) - - static void ast8250_remove(struct platform_device *pdev) - { -- struct ast8250_data *data = platform_get_drvdata(pdev); -+ struct ast8250_data *data = platform_get_drvdata(pdev); - - if (data->is_vuart) - ast8250_vuart_set_enable(data, false); - -- serial8250_unregister_port(data->line); -+ serial8250_unregister_port(data->line); - } - - static const struct dev_pm_ops ast8250_pm_ops = { -diff --git a/include/linux/soc/aspeed/aspeed-udma.h b/include/linux/soc/aspeed/aspeed-udma.h -index 1ef43e1a7..439d901c1 100644 ---- a/include/linux/soc/aspeed/aspeed-udma.h -+++ b/include/linux/soc/aspeed/aspeed-udma.h -@@ -1,7 +1,7 @@ - #ifndef __ASPEED_UDMA_H__ - #define __ASPEED_UDMA_H__ - --typedef void (*aspeed_udma_cb_t)(int fifo_rwptr, void *id); -+typedef void (*aspeed_udma_cb_t)(int rb_rwptr, void *id); - - enum aspeed_udma_ops { - ASPEED_UDMA_OP_ENABLE, -@@ -15,11 +15,9 @@ void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr); - void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op); - void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op); - --int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, -- struct kfifo *fifo, u32 fifo_sz, -+int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, - aspeed_udma_cb_t cb, void *id, bool en_tmout); --int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, -- struct kfifo *fifo, u32 fifo_sz, -+int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, - aspeed_udma_cb_t cb, void *id, bool en_tmout); - - int aspeed_udma_free_tx_chan(u32 ch_no); --- -2.34.1 - diff --git a/patches-sonic/0002-aspeed-ast2700-non-aspeed-deps-update-to-6.12.94-00.07.04.patch b/patches-sonic/0002-aspeed-ast2700-non-aspeed-deps-update-to-6.12.94-00.07.04.patch new file mode 100644 index 000000000..e749ebe4e --- /dev/null +++ b/patches-sonic/0002-aspeed-ast2700-non-aspeed-deps-update-to-6.12.94-00.07.04.patch @@ -0,0 +1,8038 @@ +From: Chandrasekaran Swaminathan +Date: Wed, 09 Sep 2026 15:51:49 +0000 +Subject: [PATCH] Aspeed AST2700 support: new non-Aspeed dependency subsystems + +New, self-contained non-Aspeed subsystems the Aspeed image depends +on (i3c/mctp, jtag, dwc TRNG, mctp-pcie-vdm, xdma trace), from a +fresh Aspeed merge at v00.07.04 on the 6.12.94 SONiC kernel. + +Signed-off-by: Chandrasekaran Swaminathan +--- +diff --git a/drivers/char/hw_random/dwc/Kconfig b/drivers/char/hw_random/dwc/Kconfig +--- a/drivers/char/hw_random/dwc/Kconfig 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/Kconfig 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,18 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# DWC Hardware Random Number Generator (RNG) configuration ++# ++ ++config HW_RANDOM_DWC ++ tristate "DesignWare Cores HW Random Number Generator support" ++ depends on HW_RANDOM ++ depends on ARCH_ASPEED || COMPILE_TEST ++ help ++ This driver provides kernel-side support for the DWC ++ Random Number Generator hardware found on Aspeed SoCs. ++ ++ To compile this driver as a module, choose M here. the ++ module will be called dwc-rng. ++ ++ If unsure, say Y. ++ +diff --git a/drivers/char/hw_random/dwc/Makefile b/drivers/char/hw_random/dwc/Makefile +--- a/drivers/char/hw_random/dwc/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/Makefile 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,22 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++ccflags-y := -I $(srctree)/drivers/char/hw_random/dwc/src/trng/include \ ++ -I $(srctree)/drivers/char/hw_random/dwc/src/pdu/linux/include ++ ++obj-$(CONFIG_HW_RANDOM_DWC) += elppdu.o ++elppdu-objs := src/pdu/linux/kernel/pdu.o \ ++ src/pdu/common/pdu/pdu_dev32.o \ ++ ++obj-$(CONFIG_HW_RANDOM_DWC) += elpmem.o ++elpmem-objs := src/pdu/linux/kernel/spacc_mem.o \ ++ ++obj-$(CONFIG_HW_RANDOM_DWC) += nisttrng.o ++nisttrng-objs := src/trng/kernel/nist_trng.o \ ++ src/trng/trng/nist_trng.o \ ++ src/trng/trng/nist_trng_private.o \ ++ ++clean: ++ @find \( -name '*.o' \ ++ -o -name '*.a' \ ++ -o -name '*.order' \ ++ \) -type f -print | xargs rm -rvf +diff --git a/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h b/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h +--- a/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/pdu/common/include/elppdu_error.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,96 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef SYNPDU_ERROR_H_ ++#define SYNPDU_ERROR_H_ ++ ++/* ++ * Common error definitions. Be sure to update pdu_error_code when changing ++ * anything in this list. ++ */ ++ ++#define CRYPTO_OK (0) ++#define CRYPTO_FAILED (-1) ++#define CRYPTO_INPROGRESS (-2) ++#define CRYPTO_INVALID_HANDLE (-3) ++#define CRYPTO_INVALID_CONTEXT (-4) ++#define CRYPTO_INVALID_SIZE (-5) ++#define CRYPTO_NOT_INITIALIZED (-6) ++#define CRYPTO_NO_MEM (-7) ++#define CRYPTO_INVALID_ALG (-8) ++#define CRYPTO_INVALID_KEY_SIZE (-9) ++#define CRYPTO_INVALID_ARGUMENT (-10) ++#define CRYPTO_MODULE_DISABLED (-11) ++#define CRYPTO_NOT_IMPLEMENTED (-12) ++#define CRYPTO_INVALID_BLOCK_ALIGNMENT (-13) ++#define CRYPTO_INVALID_MODE (-14) ++#define CRYPTO_INVALID_KEY (-15) ++#define CRYPTO_AUTHENTICATION_FAILED (-16) ++#define CRYPTO_INVALID_IV_SIZE (-17) ++#define CRYPTO_MEMORY_ERROR (-18) ++#define CRYPTO_LAST_ERROR (-19) ++#define CRYPTO_HALTED (-20) ++#define CRYPTO_TIMEOUT (-21) ++#define CRYPTO_SRM_FAILED (-22) ++#define CRYPTO_COMMON_ERROR_MAX (-100) ++#define CRYPTO_INVALID_ICV_KEY_SIZE (-100) ++#define CRYPTO_INVALID_PARAMETER_SIZE (-101) ++#define CRYPTO_SEQUENCE_OVERFLOW (-102) ++#define CRYPTO_DISABLED (-103) ++#define CRYPTO_INVALID_VERSION (-104) ++#define CRYPTO_FATAL (-105) ++#define CRYPTO_INVALID_PAD (-106) ++#define CRYPTO_FIFO_FULL (-107) ++#define CRYPTO_INVALID_SEQUENCE (-108) ++#define CRYPTO_INVALID_FIRMWARE (-109) ++#define CRYPTO_NOT_FOUND (-110) ++#define CRYPTO_CMD_FIFO_INACTIVE (-111) ++#define CRYPTO_INVALID_PROTOCOL (-112) ++#define CRYPTO_REPLAY (-113) ++#define CRYPTO_NOT_INSTANTIATED (-114) ++#define CRYPTO_RESEED_REQUIRED (-115) ++ ++#endif +diff --git a/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c b/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c +--- a/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/pdu/common/pdu/pdu_dev32.c 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,165 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "elppdu.h" ++ ++void pdu_to_dev32(void *addr_, u32 *src, unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ ++ while (nword--) { ++ pdu_io_write32(addr, *src++); ++ addr += 4; ++ } ++} ++EXPORT_SYMBOL(pdu_to_dev32); ++ ++void pdu_from_dev32(u32 *dst, void *addr_, unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ ++ while (nword--) { ++ *dst++ = pdu_io_read32(addr); ++ addr += 4; ++ } ++} ++EXPORT_SYMBOL(pdu_from_dev32); ++ ++void pdu_to_dev32_big(void *addr_, const unsigned char *src, ++ unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; ++ ++ while (nword--) { ++ v = 0; ++ v = (v << 8) | ((unsigned long)*src++); ++ v = (v << 8) | ((unsigned long)*src++); ++ v = (v << 8) | ((unsigned long)*src++); ++ v = (v << 8) | ((unsigned long)*src++); ++ pdu_io_write32(addr, v); ++ addr += 4; ++ } ++} ++EXPORT_SYMBOL(pdu_to_dev32_big); ++ ++void pdu_from_dev32_big(unsigned char *dst, void *addr_, unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; ++ ++ while (nword--) { ++ v = pdu_io_read32(addr); ++ addr += 4; ++ *dst++ = (v >> 24) & 0xFF; ++ v <<= 8; ++ *dst++ = (v >> 24) & 0xFF; ++ v <<= 8; ++ *dst++ = (v >> 24) & 0xFF; ++ v <<= 8; ++ *dst++ = (v >> 24) & 0xFF; ++ v <<= 8; ++ } ++} ++EXPORT_SYMBOL(pdu_from_dev32_big); ++ ++void pdu_to_dev32_little(void *addr_, const unsigned char *src, ++ unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; ++ ++ while (nword--) { ++ v = 0; ++ v = (v >> 8) | ((unsigned long)*src++ << 24UL); ++ v = (v >> 8) | ((unsigned long)*src++ << 24UL); ++ v = (v >> 8) | ((unsigned long)*src++ << 24UL); ++ v = (v >> 8) | ((unsigned long)*src++ << 24UL); ++ pdu_io_write32(addr, v); ++ addr += 4; ++ } ++} ++EXPORT_SYMBOL(pdu_to_dev32_little); ++ ++void pdu_from_dev32_little(unsigned char *dst, void *addr_, unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; ++ ++ while (nword--) { ++ v = pdu_io_read32(addr); ++ addr += 4; ++ *dst++ = v & 0xFF; ++ v >>= 8; ++ *dst++ = v & 0xFF; ++ v >>= 8; ++ *dst++ = v & 0xFF; ++ v >>= 8; ++ *dst++ = v & 0xFF; ++ v >>= 8; ++ } ++} ++EXPORT_SYMBOL(pdu_from_dev32_little); ++ ++void pdu_to_dev32_s(void *addr, const unsigned char *src, unsigned long nword, ++ int endian) ++{ ++ if (endian) ++ pdu_to_dev32_big(addr, src, nword); ++ else ++ pdu_to_dev32_little(addr, src, nword); ++} ++EXPORT_SYMBOL(pdu_to_dev32_s); ++ ++void pdu_from_dev32_s(unsigned char *dst, void *addr, unsigned long nword, ++ int endian) ++{ ++ if (endian) ++ pdu_from_dev32_big(dst, addr, nword); ++ else ++ pdu_from_dev32_little(dst, addr, nword); ++} ++EXPORT_SYMBOL(pdu_from_dev32_s); +diff --git a/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h b/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h +--- a/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/pdu/linux/include/elppdu.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,125 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef SYNPDU_H_ ++#define SYNPDU_H_ ++ ++/* Platform Specific */ ++#include /* printk() */ ++#include /* size_t */ ++#include /* memcpy()/etc */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef PDU_BASE_ADDR ++#define PDU_BASE_ADDR 0x14c3b000 ++#endif ++ ++#ifndef PDU_BASE_IRQ ++#define PDU_BASE_IRQ 91 ++#endif ++ ++#define PDU_SINGLE_CORE 1 ++#define PDU_SINGLE_NIST_TRNG 1 ++ ++#if 1 ++#define SYNHW_PRINT printk ++#else ++#define SYNHW_PRINT(...) ++#endif ++ ++#define CPU_YIELD ++#define SYNHW_MEMCPY memcpy ++ ++// Debug modifier for printing, in linux adding KERN_DEBUG makes the output only show up in debug logs (avoids /var/log/messages) ++#define SYNHW_PRINT_DEBUG KERN_DEBUG ++ ++// Locking ++#define PDU_LOCK_TYPE spinlock_t ++#define PDU_INIT_LOCK(lock) spin_lock_init(lock) ++ ++// these are for IRQ contexts ++#define PDU_LOCK(lock, flags) spin_lock_irqsave(lock, flags) ++#define PDU_UNLOCK(lock, flags) spin_unlock_irqrestore(lock, flags) ++ ++// these are for bottom half BH contexts ++#define PDU_LOCK_TYPE_BH struct mutex ++#define PDU_INIT_LOCK_BH(lock) mutex_init(lock) ++#define PDU_LOCK_BH(lock) mutex_lock(lock) ++#define PDU_UNLOCK_BH(lock) mutex_unlock(lock) ++ ++#include "../../common/include/elppdu_error.h" ++ ++void *pdu_linux_map_regs(struct device *dev, struct resource *regs); ++ ++void pdu_io_write32(void *addr, unsigned long val); ++void pdu_io_cached_write32(void *addr, unsigned long val, u32 *cache); ++unsigned long pdu_io_read32(void *addr); ++ ++void pdu_to_dev32(void *addr, u32 *src, unsigned long nword); ++void pdu_from_dev32(u32 *dst, void *addr, unsigned long nword); ++void pdu_to_dev32_big(void *addr, const unsigned char *src, unsigned long nword); ++void pdu_from_dev32_big(unsigned char *dst, void *addr, unsigned long nword); ++void pdu_to_dev32_little(void *addr, const unsigned char *src, unsigned long nword); ++void pdu_from_dev32_little(unsigned char *dst, void *addr, unsigned long nword); ++void pdu_from_dev32_s(unsigned char *dst, void *addr, unsigned long nword, int endian); ++void pdu_to_dev32_s(void *addr, const unsigned char *src, unsigned long nword, int endian); ++ ++void *pdu_malloc(unsigned long n); ++void pdu_free(void *p); ++ ++int pdu_error_code(int code); ++ ++#endif ++ +diff --git a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c +--- a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/pdu.c 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2011-2017 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++ ++#include "elppdu.h" ++ ++static bool trace_io; ++module_param(trace_io, bool, 0600); ++MODULE_PARM_DESC(trace_io, "Trace MMIO reads/writes"); ++ ++void *pdu_linux_map_regs(struct device *dev, struct resource *regs) ++{ ++ return devm_ioremap_resource(dev, regs); ++} ++EXPORT_SYMBOL(pdu_linux_map_regs); ++ ++void pdu_io_write32(void *addr, unsigned long val) ++{ ++ if (trace_io) ++ SYNHW_PRINT("PDU: write %.8lx -> %p\n", val, addr); ++ ++ writel(val, addr); ++} ++EXPORT_SYMBOL(pdu_io_write32); ++ ++void pdu_io_cached_write32(void *addr, unsigned long val, uint32_t *cache) ++{ ++ if (*cache == val) { ++ if (trace_io) { ++ SYNHW_PRINT("PDU: write %.8lx -> %p (cached)\n", val, ++ addr); ++ } ++ return; ++ } ++ ++ *cache = val; ++ pdu_io_write32(addr, val); ++} ++EXPORT_SYMBOL(pdu_io_cached_write32); ++ ++unsigned long pdu_io_read32(void *addr) ++{ ++ unsigned long val; ++ ++ val = readl(addr); ++ ++ if (trace_io) ++ SYNHW_PRINT("PDU: read %.8lx <- %p\n", val, addr); ++ ++ return val; ++} ++EXPORT_SYMBOL(pdu_io_read32); ++ ++/* Platform specific memory allocation */ ++void *pdu_malloc(unsigned long n) ++{ ++ return vmalloc(n); ++} ++ ++void pdu_free(void *p) ++{ ++ vfree(p); ++} ++ ++/* Convert SDK error codes to corresponding kernel error codes. */ ++int pdu_error_code(int code) ++{ ++ switch (code) { ++ case CRYPTO_INPROGRESS: ++ return -EINPROGRESS; ++ case CRYPTO_INVALID_HANDLE: ++ case CRYPTO_INVALID_CONTEXT: ++ return -ENXIO; ++ case CRYPTO_NOT_INITIALIZED: ++ return -ENODATA; ++ case CRYPTO_INVALID_SIZE: ++ case CRYPTO_INVALID_ALG: ++ case CRYPTO_INVALID_KEY_SIZE: ++ case CRYPTO_INVALID_ARGUMENT: ++ case CRYPTO_INVALID_BLOCK_ALIGNMENT: ++ case CRYPTO_INVALID_MODE: ++ case CRYPTO_INVALID_KEY: ++ case CRYPTO_INVALID_IV_SIZE: ++ case CRYPTO_INVALID_ICV_KEY_SIZE: ++ case CRYPTO_INVALID_PARAMETER_SIZE: ++ case CRYPTO_REPLAY: ++ case CRYPTO_INVALID_PROTOCOL: ++ case CRYPTO_RESEED_REQUIRED: ++ return -EINVAL; ++ case CRYPTO_NOT_IMPLEMENTED: ++ case CRYPTO_MODULE_DISABLED: ++ return -ENOTSUPP; ++ case CRYPTO_NO_MEM: ++ return -ENOMEM; ++ case CRYPTO_INVALID_PAD: ++ case CRYPTO_INVALID_SEQUENCE: ++ return -EILSEQ; ++ case CRYPTO_MEMORY_ERROR: ++ return -EIO; ++ case CRYPTO_TIMEOUT: ++ return -ETIMEDOUT; ++ case CRYPTO_HALTED: ++ return -ECANCELED; ++ case CRYPTO_AUTHENTICATION_FAILED: ++ case CRYPTO_SEQUENCE_OVERFLOW: ++ case CRYPTO_INVALID_VERSION: ++ return -EPROTO; ++ case CRYPTO_FIFO_FULL: ++ return -EBUSY; ++ case CRYPTO_SRM_FAILED: ++ case CRYPTO_DISABLED: ++ case CRYPTO_LAST_ERROR: ++ return -EAGAIN; ++ case CRYPTO_FAILED: ++ case CRYPTO_FATAL: ++ return -EIO; ++ case CRYPTO_INVALID_FIRMWARE: ++ return -ENOEXEC; ++ case CRYPTO_NOT_FOUND: ++ return -ENOENT; ++ } ++ ++ /* ++ * Any unrecognized code is either success (i.e., zero) or a negative ++ * error code, which may be meaningless but at least will still be ++ * recognized as an error. ++ */ ++ return code; ++} ++EXPORT_SYMBOL(pdu_error_code); ++ ++static int __init pdu_mod_init(void) ++{ ++ return 0; ++} ++ ++static void __exit pdu_mod_exit(void) ++{ ++} ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Synopsys, Inc."); ++module_init(pdu_mod_init); ++module_exit(pdu_mod_exit); +diff --git a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c +--- a/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/pdu/linux/kernel/spacc_mem.c 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,191 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2011-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "elppdu.h" ++ ++static unsigned long vex_baseaddr = PDU_BASE_ADDR; ++module_param_named(baseaddr, vex_baseaddr, ulong, 0); ++MODULE_PARM_DESC(baseaddr, "Hardware base address (default " __stringify(PDU_BASE_ADDR) ")"); ++ ++// max of 16 devices ++#define MAX_DEV 16 ++ ++static struct platform_device *devices[MAX_DEV]; ++static int dev_id; ++ ++static void register_device(const char *name, int id, ++ const struct resource *res, unsigned int num) ++{ ++ char suffix[16] = ""; ++ struct platform_device_info pdevinfo = { ++ .name = name, ++ .id = id, ++ .res = res, ++ .num_res = num, ++ .dma_mask = 0xffffffff, ++ }; ++ ++ if (dev_id >= MAX_DEV) { ++ pr_err("Too many devices; increase MAX_DEV.\n"); ++ return; ++ } ++ ++ devices[dev_id] = platform_device_register_full(&pdevinfo); ++ if (IS_ERR(devices[dev_id])) { ++ if (id >= 0) ++ snprintf(suffix, sizeof(suffix), ".%d", id); ++ pr_err("Failed to register %s%s\n", name, suffix); ++ ++ devices[dev_id] = NULL; ++ return; ++ } ++ ++ dev_id++; ++} ++ ++static int __init get_irq_num(unsigned int irq_num) ++{ ++ if (IS_ENABLED(CONFIG_ARCH_ZYNQ)) { ++ struct of_phandle_args args = { 0 }; ++ ++ /* ++ * Since this driver is for non-DT use but Zynq uses DT to setup IRQs, ++ * find the GIC by searching for its DT node then manually create the ++ * IRQ mappings. ++ */ ++ ++ do { ++ args.np = of_find_node_with_property(args.np, ++ "interrupt-controller"); ++ if (!args.np) { ++ pr_err("cannot find IRQ controller"); ++ return -ENODEV; ++ } ++ } while (!of_device_is_compatible(args.np, "arm,cortex-a9-gic")); ++ ++ if (irq_num < 32 || irq_num >= 96) { ++ pr_err("SPI interrupts must be in the range [32,96) on Zynq\n"); ++ return -EINVAL; ++ } ++ ++ args.args_count = 3; ++ args.args[0] = 0; /* SPI */ ++ args.args[1] = irq_num - 32; ++ args.args[2] = 4; /* Active high, level-sensitive */ ++ ++ irq_num = irq_create_of_mapping(&args); ++ of_node_put(args.np); ++ if (irq_num == 0) ++ return -EINVAL; ++ } ++ ++ if (irq_num > INT_MAX) ++ return -EINVAL; ++ ++ return irq_num; ++} ++ ++static int __init pdu_vex_mod_init(void) ++{ ++ int irq_num = get_irq_num(PDU_BASE_IRQ); ++ struct resource res[2]; ++#ifndef PDU_SINGLE_CORE ++ void *pdu_mem; ++ int i, rc; ++#endif ++ ++ if (irq_num >= 0) { ++ res[1] = (struct resource){ ++ .start = irq_num, ++ .end = irq_num, ++ .flags = IORESOURCE_IRQ, ++ }; ++ } else { ++ res[1] = (struct resource){ 0 }; ++ pr_err("IRQ setup failed (error %d), not using IRQs\n", ++ irq_num); ++ } ++ ++#ifdef PDU_SINGLE_BASIC_TRNG ++ res[0] = (struct resource){ ++ .start = vex_baseaddr, ++ .end = vex_baseaddr + 0x80 - 1, ++ .flags = IORESOURCE_MEM, ++ }; ++ register_device("basic_trng", -1, res, 2); ++#endif ++ ++#ifdef PDU_SINGLE_NIST_TRNG ++ res[0] = (struct resource){ ++ .start = vex_baseaddr, ++ .end = vex_baseaddr + 0x800 - 1, ++ .flags = IORESOURCE_MEM, ++ }; ++ register_device("nist_trng", -1, res, 2); ++#endif ++ ++ return 0; ++} ++module_init(pdu_vex_mod_init); ++ ++static void __exit pdu_vex_mod_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_DEV; i++) ++ platform_device_unregister(devices[i]); ++} ++module_exit(pdu_vex_mod_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Synopsys, Inc."); +diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h +--- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,63 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef NISTTRNG_H ++#define NISTTRNG_H ++ ++#include "synversion.h" ++#include "elppdu.h" ++#include "nisttrng_hw.h" ++#include "nisttrng_common.h" ++#include "nisttrng_private.h" ++ ++int nisttrng_init(struct nist_trng_state *state, u32 *base); ++int nisttrng_instantiate(struct nist_trng_state *state, int req_sec_strength, int pred_resist, void *personal_str); ++int nisttrng_uninstantiate(struct nist_trng_state *state); ++int nisttrng_reseed(struct nist_trng_state *state, int pred_resist, void *addin_str); ++int nisttrng_generate(struct nist_trng_state *state, void *random_bits, unsigned long req_num_bytes, int req_sec_strength, int pred_resist, void *addin_str); ++int nisttrng_rbc(struct nist_trng_state *state, int enable, int rbc_num, int rate, int urun_blnk); ++int nisttrng_generate_public_vtrng(struct nist_trng_state *state, void *random_bits, unsigned long req_num_bytes, int vtrng); ++#endif +diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h +--- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_common.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,144 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++// ------------------------------------------------------------------------ ++// ++// (C) COPYRIGHT 2012 - 2016 SYNOPSYS, INC. ++// ALL RIGHTS RESERVED ++// ++// (C) COPYRIGHT 2012-2016 Synopsys, Inc. ++// This Synopsys software and all associated documentation are ++// proprietary to Synopsys, Inc. and may only be used pursuant ++// to the terms and conditions of a written license agreement ++// with Synopsys, Inc. All other use, reproduction, modification, ++// or distribution of the Synopsys software or the associated ++// documentation is strictly prohibited. ++// ++// ------------------------------------------------------------------------ ++ ++#ifndef NISTTRNG_COMMON_H ++#define NISTTRNG_COMMON_H ++ ++#define NIST_TRNG_RETRY_MAX 5000000UL ++ ++#define NIST_DFLT_MAX_BITS_PER_REQ BIT(19) ++#define NIST_DFLT_MAX_REQ_PER_SEED BIT(48) ++ ++/* Do not change the following parameters */ ++#define NIST_TRNG_DFLT_MAX_REJECTS 10 ++ ++#define DEBUG(...) ++//#define DEBUG(...) printk(__VA_ARGS__) ++ ++enum nisttrng_sec_strength { ++ SEC_STRNT_AES128 = 0, ++ SEC_STRNT_AES256 = 1 ++}; ++ ++enum nisttrng_drbg_arch { ++ AES128 = 0, ++ AES256 = 1 ++}; ++ ++enum nisttrng_current_state { ++ NIST_TRNG_STATE_INITIALIZE = 0, ++ NIST_TRNG_STATE_UNINSTANTIATE, ++ NIST_TRNG_STATE_INSTANTIATE, ++ NIST_TRNG_STATE_RESEED, ++ NIST_TRNG_STATE_GENERATE ++}; ++ ++struct nist_trng_state { ++ u32 *base; ++ ++ /* Hardware features and build ID */ ++ struct { ++ struct { ++ enum nisttrng_drbg_arch drbg_arch; ++ unsigned int extra_ps_present, ++ secure_rst_state, ++ diag_level_basic_trng, ++ diag_level_stat_hlt, ++ diag_level_ns; ++ } features; ++ ++ struct { ++ unsigned int ext_enum, ++ ext_ver, ++ rel_num; ++ } corekit_rel; ++ ++ struct { ++ unsigned int core_type, ++ bg8, ++ cdc_synch_depth, ++ background_noise, ++ edu_present, ++ aes_datapath, ++ aes_max_key_size, ++ personilzation_str; ++ } build_cfg0; ++ ++ struct { ++ unsigned int num_raw_noise_blks, ++ sticky_startup, ++ auto_correlation_test, ++ mono_bit_test, ++ run_test, ++ poker_test, ++ raw_ht_adap_test, ++ raw_ht_rep_test, ++ ent_src_rep_smpl_size, ++ ent_src_rep_test, ++ ent_src_rep_min_entropy; ++ } build_cfg1; ++ ++ struct { ++ unsigned int rbc2_rate_width, ++ rbc1_rate_width, ++ rbc0_rate_width, ++ public_vtrng_channels, ++ esm_channel, ++ rbc_channels, ++ fifo_depth; ++ } edu_build_cfg0; ++ } config; ++ ++ /* status */ ++ struct { ++ //nist_trng_current_state current_state; ++ enum nisttrng_current_state current_state; // old for now ++ unsigned int nonce_mode, ++ secure_mode, ++ pred_resist; ++ //nist_trng_sec_strength sec_strength; ++ enum nisttrng_sec_strength sec_strength; ++ unsigned int pad_ps_addin; ++ unsigned int alarm_code; ++ // Private VTRNG STAT, all the public trng will have the same STAT as public TRNG in terms of ++ // rnc_enabled and seed_enum ++ struct { ++ unsigned int seed_enum, ++ rnc_enabled; ++ } edu_vstat; ++ } status; ++ ++ /* reminders and alarms */ ++ struct { ++ unsigned long max_bits_per_req; ++ unsigned long long max_req_per_seed; ++ unsigned long bits_per_req_left; ++ unsigned long long req_per_seed_left; ++ } counters; ++}; ++ ++#define nist_trng_zero_status(x) \ ++ memset(&((x)->status), 0, sizeof((x)->status)) ++ ++#define DRBG_INSTANTIATED(cs) \ ++ ((((cs) == NIST_TRNG_STATE_INSTANTIATE) || \ ++ ((cs) == NIST_TRNG_STATE_RESEED) || \ ++ ((cs) == NIST_TRNG_STATE_GENERATE)) ? 1 : 0) ++ ++#define REQ_SEC_STRENGTH_IS_VALID(sec_st) \ ++ ((((sec_st) > 0) && ((sec_st) <= 256)) ? 1 : 0) ++ ++#endif +diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h +--- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_hw.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,457 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef NISTTRNG_HW_H ++#define NISTTRNG_HW_H ++ ++/* HW related Parameters */ ++#define NIST_TRNG_RAND_BLK_SIZE_BITS 128 ++#define CHX_URUN_BLANK_AFTER_RESET 0x3 ++ ++/* registers */ ++#define NIST_TRNG_REG_CTRL 0x00 ++#define NIST_TRNG_REG_MODE 0x01 ++#define NIST_TRNG_REG_SMODE 0x02 ++#define NIST_TRNG_REG_STAT 0x03 ++#define NIST_TRNG_REG_IE 0x04 ++#define NIST_TRNG_REG_ISTAT 0x05 ++#define NIST_TRNG_REG_ALARM 0x06 ++#define NIST_TRNG_REG_COREKIT_REL 0x07 ++#define NIST_TRNG_REG_FEATURES 0x08 ++#define NIST_TRNG_REG_RAND0 0x09 ++#define NIST_TRNG_REG_RAND1 0x0A ++#define NIST_TRNG_REG_RAND2 0x0B ++#define NIST_TRNG_REG_RAND3 0x0C ++#define NIST_TRNG_REG_NPA_DATA0 0x0D ++#define NIST_TRNG_REG_NPA_DATA1 0x0E ++#define NIST_TRNG_REG_NPA_DATA2 0x0F ++#define NIST_TRNG_REG_NPA_DATA3 0x10 ++#define NIST_TRNG_REG_NPA_DATA4 0x11 ++#define NIST_TRNG_REG_NPA_DATA5 0x12 ++#define NIST_TRNG_REG_NPA_DATA6 0x13 ++#define NIST_TRNG_REG_NPA_DATA7 0x14 ++#define NIST_TRNG_REG_NPA_DATA8 0x15 ++#define NIST_TRNG_REG_NPA_DATA9 0x16 ++#define NIST_TRNG_REG_NPA_DATA10 0x17 ++#define NIST_TRNG_REG_NPA_DATA11 0x18 ++#define NIST_TRNG_REG_NPA_DATA12 0x19 ++#define NIST_TRNG_REG_NPA_DATA13 0x1A ++#define NIST_TRNG_REG_NPA_DATA14 0x1B ++#define NIST_TRNG_REG_NPA_DATA15 0x1C ++#define NIST_TRNG_REG_SEED0 0x1D ++#define NIST_TRNG_REG_SEED1 0x1E ++#define NIST_TRNG_REG_SEED2 0x1F ++#define NIST_TRNG_REG_SEED3 0x20 ++#define NIST_TRNG_REG_SEED4 0x21 ++#define NIST_TRNG_REG_SEED5 0x22 ++#define NIST_TRNG_REG_SEED6 0x23 ++#define NIST_TRNG_REG_SEED7 0x24 ++#define NIST_TRNG_REG_SEED8 0x25 ++#define NIST_TRNG_REG_SEED9 0x26 ++#define NIST_TRNG_REG_SEED10 0x27 ++#define NIST_TRNG_REG_SEED11 0x28 ++#define NIST_TRNG_REG_TIME_TO_SEED 0x34 ++#define NIST_TRNG_REG_IA_RDATA 0x38 ++#define NIST_TRNG_REG_IA_WDATA 0x39 ++#define NIST_TRNG_REG_IA_ADDR 0x3A ++#define NIST_TRNG_REG_IA_CMD 0x3B ++#define NIST_TRNG_REG_BUILD_CFG0 0x3C ++#define NIST_TRNG_REG_BUILD_CFG1 0x3D ++ ++/* nist edu registers */ ++#define NIST_TRNG_EDU_RNC_CTRL 0x100 ++#define NIST_TRNG_EDU_FLUSH_CTRL 0x101 ++#define NIST_TRNG_EDU_RESEED_CNTR 0x102 ++#define NIST_TRNG_EDU_RBC_CTRL 0x104 ++#define NIST_TRNG_EDU_STAT 0x106 ++#define NIST_TRNG_EDU_IE 0x108 ++#define NIST_TRNG_EDU_ISTAT 0x109 ++#define NIST_TRNG_EDU_BUILD_CFG0 0x12C ++#define NIST_TRNG_EDU_VCTRL 0x138 ++#define NIST_TRNG_EDU_VSTAT 0x139 ++#define NIST_TRNG_EDU_VIE 0x13A ++#define NIST_TRNG_EDU_VISTAT 0x13B ++#define NIST_TRNG_EDU_VRAND_0 0x13C ++#define NIST_TRNG_EDU_VRAND_1 0x13D ++#define NIST_TRNG_EDU_VRAND_2 0x13E ++#define NIST_TRNG_EDU_VRAND_3 0x13F ++ ++/* edu vtrng registers */ ++#define NIST_TRNG_EDU_VTRNG_VCTRL0 0x180 ++#define NIST_TRNG_EDU_VTRNG_VSTAT0 0x181 ++#define NIST_TRNG_EDU_VTRNG_VIE0 0x182 ++#define NIST_TRNG_EDU_VTRNG_VISTAT0 0x183 ++#define NIST_TRNG_EDU_VTRNG_VRAND0_0 0x184 ++#define NIST_TRNG_EDU_VTRNG_VRAND0_1 0x185 ++#define NIST_TRNG_EDU_VTRNG_VRAND0_2 0x186 ++#define NIST_TRNG_EDU_VTRNG_VRAND0_3 0x187 ++#define NIST_TRNG_EDU_VTRNG_VCTRL1 0x188 ++#define NIST_TRNG_EDU_VTRNG_VSTAT1 0x189 ++#define NIST_TRNG_EDU_VTRNG_VIE1 0x18A ++#define NIST_TRNG_EDU_VTRNG_VISTAT1 0x18B ++#define NIST_TRNG_EDU_VTRNG_VRAND1_0 0x18C ++#define NIST_TRNG_EDU_VTRNG_VRAND1_1 0x18D ++#define NIST_TRNG_EDU_VTRNG_VRAND1_2 0x18E ++#define NIST_TRNG_EDU_VTRNG_VRAND1_3 0x18F ++#define NIST_TRNG_EDU_VTRNG_VCTRL2 0x190 ++#define NIST_TRNG_EDU_VTRNG_VSTAT2 0x191 ++#define NIST_TRNG_EDU_VTRNG_VIE2 0x192 ++#define NIST_TRNG_EDU_VTRNG_VISTAT2 0x193 ++#define NIST_TRNG_EDU_VTRNG_VRAND2_0 0x194 ++#define NIST_TRNG_EDU_VTRNG_VRAND2_1 0x195 ++#define NIST_TRNG_EDU_VTRNG_VRAND2_2 0x196 ++#define NIST_TRNG_EDU_VTRNG_VRAND2_3 0x197 ++#define NIST_TRNG_EDU_VTRNG_VCTRL3 0x198 ++#define NIST_TRNG_EDU_VTRNG_VSTAT3 0x199 ++#define NIST_TRNG_EDU_VTRNG_VIE3 0x19A ++#define NIST_TRNG_EDU_VTRNG_VISTAT3 0x19B ++#define NIST_TRNG_EDU_VTRNG_VRAND3_0 0x19C ++#define NIST_TRNG_EDU_VTRNG_VRAND3_1 0x19D ++#define NIST_TRNG_EDU_VTRNG_VRAND3_2 0x19E ++#define NIST_TRNG_EDU_VTRNG_VRAND3_3 0x19F ++#define NIST_TRNG_EDU_VTRNG_VCTRL4 0x1A0 ++#define NIST_TRNG_EDU_VTRNG_VSTAT4 0x1A1 ++#define NIST_TRNG_EDU_VTRNG_VIE4 0x1A2 ++#define NIST_TRNG_EDU_VTRNG_VISTAT4 0x1A3 ++#define NIST_TRNG_EDU_VTRNG_VRAND4_0 0x1A4 ++#define NIST_TRNG_EDU_VTRNG_VRAND4_1 0x1A5 ++#define NIST_TRNG_EDU_VTRNG_VRAND4_2 0x1A6 ++#define NIST_TRNG_EDU_VTRNG_VRAND4_3 0x1A7 ++#define NIST_TRNG_EDU_VTRNG_VCTRL5 0x1A8 ++#define NIST_TRNG_EDU_VTRNG_VSTAT5 0x1A9 ++#define NIST_TRNG_EDU_VTRNG_VIE5 0x1AA ++#define NIST_TRNG_EDU_VTRNG_VISTAT5 0x1AB ++#define NIST_TRNG_EDU_VTRNG_VRAND5_0 0x1AC ++#define NIST_TRNG_EDU_VTRNG_VRAND5_1 0x1AD ++#define NIST_TRNG_EDU_VTRNG_VRAND5_2 0x1AE ++#define NIST_TRNG_EDU_VTRNG_VRAND5_3 0x1AF ++#define NIST_TRNG_EDU_VTRNG_VCTRL6 0x1B0 ++#define NIST_TRNG_EDU_VTRNG_VSTAT6 0x1B1 ++#define NIST_TRNG_EDU_VTRNG_VIE6 0x1B2 ++#define NIST_TRNG_EDU_VTRNG_VISTAT6 0x1B3 ++#define NIST_TRNG_EDU_VTRNG_VRAND6_0 0x1B4 ++#define NIST_TRNG_EDU_VTRNG_VRAND6_1 0x1B5 ++#define NIST_TRNG_EDU_VTRNG_VRAND6_2 0x1B6 ++#define NIST_TRNG_EDU_VTRNG_VRAND6_3 0x1B7 ++#define NIST_TRNG_EDU_VTRNG_VCTRL7 0x1B8 ++#define NIST_TRNG_EDU_VTRNG_VSTAT7 0x1B9 ++#define NIST_TRNG_EDU_VTRNG_VIE7 0x1BA ++#define NIST_TRNG_EDU_VTRNG_VISTAT7 0x1BB ++#define NIST_TRNG_EDU_VTRNG_VRAND7_0 0x1BC ++#define NIST_TRNG_EDU_VTRNG_VRAND7_1 0x1BD ++#define NIST_TRNG_EDU_VTRNG_VRAND7_2 0x1BE ++#define NIST_TRNG_EDU_VTRNG_VRAND7_3 0x1BF ++ ++#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_NOP 0x0 ++#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_GET_RANDOM 0x1 ++#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_INIT 0x2 ++ ++#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_MASK 0x3Ul ++#define NIST_TRNG_EDU_VTRNG_VCTRL_CMD_SET(y, x) (((y) & ~(NIST_TRNG_EDU_VTRNG_VCTRL_CMD_MASK)) | ((x))) ++ ++/* CTRL */ ++#define NIST_TRNG_REG_CTRL_CMD_NOP 0 ++#define NIST_TRNG_REG_CTRL_CMD_GEN_NOISE 1 ++#define NIST_TRNG_REG_CTRL_CMD_GEN_NONCE 2 ++#define NIST_TRNG_REG_CTRL_CMD_CREATE_STATE 3 ++#define NIST_TRNG_REG_CTRL_CMD_RENEW_STATE 4 ++#define NIST_TRNG_REG_CTRL_CMD_REFRESH_ADDIN 5 ++#define NIST_TRNG_REG_CTRL_CMD_GEN_RANDOM 6 ++#define NIST_TRNG_REG_CTRL_CMD_ADVANCE_STATE 7 ++#define NIST_TRNG_REG_CTRL_CMD_KAT 8 ++#define NIST_TRNG_REG_CTRL_CMD_ZEROIZE 15 ++ ++/* EDU CTRL */ ++#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_DISABLE_TO_HOLD 0 ++#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE 1 ++#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_DISABLE_TO_IDLE 2 ++#define NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE 3 ++ ++#define NIST_TRNG_EDU_RNC_CTRL_CMD_MASK 0x3Ul ++#define NIST_TRNG_EDU_RNC_CTRL_CMD_SET(y, x) (((y) & ~(NIST_TRNG_EDU_RNC_CTRL_CMD_MASK)) | ((x))) ++ ++/* EDU_FLUSH_CTRL */ ++#define _NIST_TRNG_EDU_FLUSH_CTRL_CH2_RBC 3 ++#define _NIST_TRNG_EDU_FLUSH_CTRL_CH1_RBC 2 ++#define _NIST_TRNG_EDU_FLUSH_CTRL_CH0_RBC 1 ++#define _NIST_TRNG_EDU_FLUSH_CTRL_FIFO 0 ++ ++#define NIST_TRNG_EDU_FLUSH_CTRL_CH2_RBC BIT(_NIST_TRNG_EDU_FLUSH_CTRL_CH2_RBC) ++#define NIST_TRNG_EDU_FLUSH_CTRL_CH1_RBC BIT(_NIST_TRNG_EDU_FLUSH_CTRL_CH1_RBC) ++#define NIST_TRNG_EDU_FLUSH_CTRL_CH0_RBC BIT(_NIST_TRNG_EDU_FLUSH_CTRL_CH0_RBC) ++#define NIST_TRNG_EDU_FLUSH_CTRL_FIFO BIT(_NIST_TRNG_EDU_FLUSH_CTRL_FIFO) ++ ++/*EDU_RBC_CTRL*/ ++#define _NIST_TRNG_EDU_RBC_CTRL_CH2_URUN_BLANK 28 ++#define _NIST_TRNG_EDU_RBC_CTRL_CH1_URUN_BLANK 26 ++#define _NIST_TRNG_EDU_RBC_CTRL_CH0_URUN_BLANK 24 ++#define _NIST_TRNG_EDU_RBC_CTRL_CH2_RATE 16 ++#define _NIST_TRNG_EDU_RBC_CTRL_CH1_RATE 8 ++#define _NIST_TRNG_EDU_RBC_CTRL_CH0_RATE 0 ++ ++#define _NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK 0xFUL ++#define _NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK 0x3UL ++ ++#define NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(z, y, x) (((y) & ~(_NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK << (x))) | ((z) << (x))) ++#define NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(z, y, x) (((y) & ~(_NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK << (x))) | ((z) << (x))) ++ ++#define NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(y, x) ((_NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK) & ((y) >> (x))) ++#define NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(y, x) ((_NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK) & ((y) >> (x))) ++ ++#define NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE_AFTER_RESET 0x0 ++#define NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK_AFTER_RESET 0x3 ++ ++/* MODE */ ++#define _NIST_TRNG_REG_MODE_KAT_SEL 7 ++#define _NIST_TRNG_REG_MODE_KAT_VEC 5 ++#define _NIST_TRNG_REG_MODE_ADDIN_PRESENT 4 ++#define _NIST_TRNG_REG_MODE_PRED_RESIST 3 ++#define _NIST_TRNG_REG_MODE_SEC_ALG 0 ++ ++#define NIST_TRNG_REG_MODE_ADDIN_PRESENT BIT(_NIST_TRNG_REG_MODE_ADDIN_PRESENT) ++#define NIST_TRNG_REG_MODE_PRED_RESIST BIT(_NIST_TRNG_REG_MODE_PRED_RESIST) ++#define NIST_TRNG_REG_MODE_SEC_ALG BIT(_NIST_TRNG_REG_MODE_SEC_ALG) ++ ++/* SMODE */ ++#define _NIST_TRNG_REG_SMODE_NOISE_COLLECT 31 ++#define _NIST_TRNG_REG_SMODE_INDIV_HT_DISABLE 16 ++#define _NIST_TRNG_REG_SMODE_MAX_REJECTS 2 ++#define _NIST_TRNG_REG_SMODE_MISSION_MODE 1 ++#define _NIST_TRNG_REG_SMODE_SECURE_EN _NIST_TRNG_REG_SMODE_MISSION_MODE ++#define _NIST_TRNG_REG_SMODE_NONCE 0 ++ ++#define NIST_TRNG_REG_SMODE_MAX_REJECTS(x) ((x) << _NIST_TRNG_REG_SMODE_MAX_REJECTS) ++#define NIST_TRNG_REG_SMODE_SECURE_EN(x) ((x) << _NIST_TRNG_REG_SMODE_SECURE_EN) ++#define NIST_TRNG_REG_SMODE_NONCE BIT(_NIST_TRNG_REG_SMODE_NONCE) ++ ++/* STAT */ ++#define _NIST_TRNG_REG_STAT_BUSY 31 ++#define _NIST_TRNG_REG_STAT_STARTUP_TEST_IN_PROG 10 ++#define _NIST_TRNG_REG_STAT_STARTUP_TEST_STUCK 9 ++#define _NIST_TRNG_REG_STAT_DRBG_STATE 7 ++#define _NIST_TRNG_REG_STAT_SECURE 6 ++#define _NIST_TRNG_REG_STAT_NONCE_MODE 5 ++#define _NIST_TRNG_REG_STAT_SEC_ALG 4 ++#define _NIST_TRNG_REG_STAT_LAST_CMD 0 ++ ++#define NIST_TRNG_REG_STAT_BUSY BIT(_NIST_TRNG_REG_STAT_BUSY) ++//#define NIST_TRNG_REG_STAT_DRBG_STATE (1UL<<_NIST_TRNG_REG_STAT_DRBG_STATE) ++//#define NIST_TRNG_REG_STAT_SECURE (1UL << _NIST_TRNG_REG_STAT_SECURE) ++//#define NIST_TRNG_REG_STAT_NONCE_MODE (1UL << _NIST_TRNG_REG_STAT_NONCE_MODE) ++//#define NIST_TRNG_REG_STAT_SEC_ALG (1UL << _NIST_TRNG_REG_STAT_SEC_ALG) ++//#define NIST_TRNG_REG_STAT_LAST_CMD(x) (((x) >> _NIST_TRNG_REG_STAT_LAST_CMD)&0xF) ++ ++/*EDU_STAT*/ ++ ++#define NIST_TRNG_EDU_STAT_FIFO_LEVEL(x) (((x) >> 24) & 255) ++#define NIST_TRNG_EDU_STAT_TTT_INDEX(x) (((x) >> 16) & 255) ++#define NIST_TRNG_EDU_STAT_RNC_BUSY(x) (((x) >> 3) & 7) ++#define NIST_TRNG_EDU_STAT_RNC_ENABLED(x) (((x) >> 2) & 1) ++#define NIST_TRNG_EDU_STAT_FIFO_EMPTY(x) (((x) >> 1) & 1) ++#define NIST_TRNG_EDU_STAT_FIFO_FULL(x) ((x) & 1) ++ ++/* IE */ ++#define _NIST_TRNG_REG_IE_GLBL 31 ++#define _NIST_TRNG_REG_IE_DONE 4 ++#define _NIST_TRNG_REG_IE_ALARMS 3 ++#define _NIST_TRNG_REG_IE_NOISE_RDY 2 ++#define _NIST_TRNG_REG_IE_KAT_COMPLETE 1 ++#define _NIST_TRNG_REG_IE_ZEROIZE 0 ++ ++#define NIST_TRNG_REG_IE_GLBL BIT(_NIST_TRNG_REG_IE_GLBL) ++#define NIST_TRNG_REG_IE_DONE BIT(_NIST_TRNG_REG_IE_DONE) ++#define NIST_TRNG_REG_IE_ALARMS BIT(_NIST_TRNG_REG_IE_ALARMS) ++#define NIST_TRNG_REG_IE_NOISE_RDY BIT(_NIST_TRNG_REG_IE_NOISE_RDY) ++#define NIST_TRNG_REG_IE_KAT_COMPLETE BIT(_NIST_TRNG_REG_IE_KAT_COMPLETE) ++#define NIST_TRNG_REG_IE_ZEROIZE BIT(_NIST_TRNG_REG_IE_ZEROIZE) ++ ++/* ISTAT */ ++#define _NIST_TRNG_REG_ISTAT_DONE 4 ++#define _NIST_TRNG_REG_ISTAT_ALARMS 3 ++#define _NIST_TRNG_REG_ISTAT_NOISE_RDY 2 ++#define _NIST_TRNG_REG_ISTAT_KAT_COMPLETE 1 ++#define _NIST_TRNG_REG_ISTAT_ZEROIZE 0 ++ ++#define NIST_TRNG_REG_ISTAT_DONE BIT(_NIST_TRNG_REG_ISTAT_DONE) ++#define NIST_TRNG_REG_ISTAT_ALARMS BIT(_NIST_TRNG_REG_ISTAT_ALARMS) ++#define NIST_TRNG_REG_ISTAT_NOISE_RDY BIT(_NIST_TRNG_REG_ISTAT_NOISE_RDY) ++#define NIST_TRNG_REG_ISTAT_KAT_COMPLETE BIT(_NIST_TRNG_REG_ISTAT_KAT_COMPLETE) ++#define NIST_TRNG_REG_ISTAT_ZEROIZE BIT(_NIST_TRNG_REG_ISTAT_ZEROIZE) ++ ++/*EDU_ISTAT*/ ++ ++#define _NIST_TRNG_EDU_ISTAT_CH2_RBC_URUN 8 ++#define _NIST_TRNG_EDU_ISTAT_CH1_RBC_URUN 7 ++#define _NIST_TRNG_EDU_ISTAT_CH0_RBC_URUN 6 ++#define _NIST_TRNG_EDU_ISTAT_PRIVATE_VTRNG 5 ++#define _NIST_TRNG_EDU_ISTAT_WAIT_EXP_TIMEOUT 4 ++#define _NIST_TRNG_EDU_ISTAT_RNC_DRVN_OFFLINE 3 ++#define _NIST_TRNG_EDU_ISTAT_FIFO_URUN 2 ++#define _NIST_TRNG_EDU_ISTAT_ACCESS_VIOL 1 ++#define _NIST_TRNG_EDU_ISTAT_RESEED_REMINDER 0 ++ ++#define NIST_TRNG_EDU_ISTAT_CH2_RBC_URUN BIT(_NIST_TRNG_EDU_ISTAT_CH2_RBC_URUN) ++#define NIST_TRNG_EDU_ISTAT_CH1_RBC_URUN BIT(_NIST_TRNG_EDU_ISTAT_CH1_RBC_URUN) ++#define NIST_TRNG_EDU_ISTAT_CH0_RBC_URUN BIT(_NIST_TRNG_EDU_ISTAT_CH0_RBC_URUN) ++#define NIST_TRNG_EDU_ISTAT_PRIVATE_VTRNG BIT(_NIST_TRNG_EDU_ISTAT_PRIVATE_VTRNG) ++#define NIST_TRNG_EDU_ISTAT_WAIT_EXP_TIMEOUT BIT(_NIST_TRNG_EDU_ISTAT_WAIT_EXP_TIMEOUT) ++#define NIST_TRNG_EDU_ISTAT_RNC_DRVN_OFFLINE BIT(_NIST_TRNG_EDU_ISTAT_RNC_DRVN_OFFLINE) ++#define NIST_TRNG_EDU_ISTAT_FIFO_URUN BIT(_NIST_TRNG_EDU_ISTAT_FIFO_URUN) ++#define NIST_TRNG_EDU_ISTAT_ACCESS_VIOL BIT(_NIST_TRNG_EDU_ISTAT_ACCESS_VIOL) ++#define NIST_TRNG_EDU_ISTAT_RESEED_REMINDER BIT(_NIST_TRNG_EDU_ISTAT_RESEED_REMINDER) ++ ++/* ALARMS */ ++#define NIST_TRNG_REG_ALARM_ILLEGAL_CMD_SEQ BIT(4) ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_OK 0 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_KAT_STAT 1 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_KAT 2 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_MONOBIT 3 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_RUN 4 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_LONGRUN 5 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_AUTOCORRELATION 6 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_POKER 7 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_REPETITION_COUNT 8 ++#define NIST_TRNG_REG_ALARM_FAILED_TEST_ID_ADAPATIVE_PROPORTION 9 ++ ++/* COREKIT_REL */ ++#define NIST_TRNG_REG_EXT_ENUM(x) (((x) >> 28) & 0xF) ++#define NIST_TRNG_REG_EXT_VER(x) (((x) >> 23) & 0xFF) ++#define NIST_TRNG_REG_REL_NUM(x) ((x) & 0xFFFF) ++ ++// This will be deleted ?? per comments in hw details. ie use CFG ++/* FEATURES */ ++#define NIST_TRNG_REG_FEATURES_AES_256(x) (((x) >> 9) & 1) ++#define NIST_TRNG_REG_FEATURES_EXTRA_PS_PRESENT(x) (((x) >> 8) & 1) ++#define NIST_TRNG_REG_FEATURES_DIAG_LEVEL_NS(x) (((x) >> 7) & 1) ++#define NIST_TRNG_REG_FEATURES_DIAG_LEVEL_BASIC_TRNG(x) (((x) >> 4) & 7) ++#define NIST_TRNG_REG_FEATURES_DIAG_LEVEL_ST_HLT(x) (((x) >> 1) & 7) ++#define NIST_TRNG_REG_FEATURES_SECURE_RST_STATE(x) ((x) & 1) ++ ++/* build_CFG0 */ ++#define NIST_TRNG_REG_CFG0_PERSONILIZATION_STR(x) (((x) >> 14) & 1) ++#define NIST_TRNG_REG_CFG0_AES_MAX_KEY_SIZE(x) (((x) >> 13) & 1) ++#define NIST_TRNG_REG_CFG0_AES_DATAPATH(x) (((x) >> 12) & 1) ++#define NIST_TRNG_REG_CFG0_EDU_PRESENT(x) (((x) >> 11) & 1) ++#define NIST_TRNG_REG_CFG0_BACGROUND_NOISE(x) (((x) >> 10) & 1) ++#define NIST_TRNG_REG_CFG0_CDC_SYNCH_DEPTH(x) (((x) >> 8) & 3) ++#define NIST_TRNG_REG_CFG0_BG8(x) (((x) >> 7) & 1) ++#define NIST_TRNG_REG_CFG0_CORE_TYPE(x) ((x) & 3) ++ ++/* build_CFG1 */ ++#define NIST_TRNG_REG_CFG1_ENT_SRC_REP_MIN_ENTROPY(x) (((x) >> 24) & 255) ++#define NIST_TRNG_REG_CFG1_ENT_SRC_REP_TEST(x) (((x) >> 23) & 1) ++#define NIST_TRNG_REG_CFG1_ENT_SRC_REP_SMPL_SIZE(x) (((x) >> 20) & 7) ++#define NIST_TRNG_REG_CFG1_RAW_HT_REP_TEST(x) (((x) >> 19) & 1) ++#define NIST_TRNG_REG_CFG1_RAW_HT_ADAP_TEST(x) (((x) >> 16) & 7) ++#define NIST_TRNG_REG_CFG1_POKER_TEST(x) (((x) >> 15) & 1) ++#define NIST_TRNG_REG_CFG1_RUN_TEST(x) (((x) >> 14) & 1) ++#define NIST_TRNG_REG_CFG1_MONO_BIT_TEST(x) (((x) >> 13) & 1) ++#define NIST_TRNG_REG_CFG1_AUTO_CORRELATION_TEST(x) (((x) >> 12) & 1) ++#define NIST_TRNG_REG_CFG1_STICKY_STARTUP(x) (((x) >> 8) & 1) ++#define NIST_TRNG_REG_CFG1_NUM_RAW_NOISE_BLKS(x) ((x) & 255) ++ ++/* EDU_BUILD_CFG0 */ ++#define NIST_TRNG_REG_EDU_CFG0_RBC2_RATE_WIDTH(x) (((x) >> 20) & 7) ++#define NIST_TRNG_REG_EDU_CFG0_RBC1_RATE_WIDTH(x) (((x) >> 16) & 7) ++#define NIST_TRNG_REG_EDU_CFG0_RBC0_RATE_WIDTH(x) (((x) >> 12) & 7) ++#define NIST_TRNG_REG_EDU_CFG0_PUBLIC_VTRNG_CHANNELS(x) (((x) >> 8) & 15) ++#define NIST_TRNG_REG_EDU_CFG0_ESM_CHANNEL(x) (((x) >> 6) & 1) ++#define NIST_TRNG_REG_EDU_CFG0_RBC_CHANNELS(x) (((x) >> 4) & 3) ++#define NIST_TRNG_REG_EDU_CFG0_FIFO_DEPTH(x) (((x) >> 2) & 7) ++ ++/* EDU_VSTAT */ ++#define NIST_TRNG_REG_EDU_VSTAT_BUSY(x) (((x) >> 31) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_RNC_ENABLED(x) (((x) >> 30) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SEED_ENUM(x) (((x) >> 28) & 3) ++#define NIST_TRNG_REG_EDU_VSTAT_RWUE(x) (((x) >> 27) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_RWNE(x) (((x) >> 26) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SRWE(x) (((x) >> 25) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_ANY_RW1(x) (((x) >> 24) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_BCKGRND_NOISE(x) (((x) >> 23) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_RNC_FIFO_EMPTY(x) (((x) >> 22) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI3(x) (((x) >> 15) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI2(x) (((x) >> 14) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI1(x) (((x) >> 13) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_RWI0(x) (((x) >> 12) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD3(x) (((x) >> 11) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD2(x) (((x) >> 10) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD1(x) (((x) >> 9) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD0(x) (((x) >> 8) & 1) ++#define NIST_TRNG_REG_EDU_VSTAT_CURRENT_CMD(x) (((x) >> 4) & 15) ++#define NIST_TRNG_REG_EDU_VSTAT_LAST_CMD(x) ((x) & 15) ++ ++#define _NIST_TRNG_REG_SMODE_MAX_REJECTS_MASK 255UL ++#define _NIST_TRNG_REG_SMODE_SECURE_EN_MASK 1UL ++#define _NIST_TRNG_REG_SMODE_NONCE_MASK 1UL ++#define _NIST_TRNG_REG_MODE_SEC_ALG_MASK 1UL ++#define _NIST_TRNG_REG_MODE_ADDIN_PRESENT_MASK 1UL ++#define _NIST_TRNG_REG_MODE_PRED_RESIST_MASK 1UL ++#define _NIST_TRNG_REG_MODE_KAT_SEL_MASK 3UL ++#define _NIST_TRNG_REG_MODE_KAT_VEC_MASK 3UL ++#define _NIST_TRNG_REG_STAT_DRBG_STATE_MASK 3UL ++#define _NIST_TRNG_REG_STAT_SECURE_MASK 1UL ++#define _NIST_TRNG_REG_STAT_NONCE_MASK 1UL ++ ++#define NIST_TRNG_REG_SMODE_SET_MAX_REJECTS(y, x) (((y) & ~(_NIST_TRNG_REG_SMODE_MAX_REJECTS_MASK << _NIST_TRNG_REG_SMODE_MAX_REJECTS)) | ((x) << _NIST_TRNG_REG_SMODE_MAX_REJECTS)) ++#define NIST_TRNG_REG_SMODE_SET_SECURE_EN(y, x) (((y) & ~(_NIST_TRNG_REG_SMODE_SECURE_EN_MASK << _NIST_TRNG_REG_SMODE_SECURE_EN)) | ((x) << _NIST_TRNG_REG_SMODE_SECURE_EN)) ++#define NIST_TRNG_REG_SMODE_SET_NONCE(y, x) (((y) & ~(_NIST_TRNG_REG_SMODE_NONCE_MASK << _NIST_TRNG_REG_SMODE_NONCE)) | ((x) << _NIST_TRNG_REG_SMODE_NONCE)) ++#define NIST_TRNG_REG_SMODE_GET_MAX_REJECTS(x) (((x) >> _NIST_TRNG_REG_SMODE_MAX_REJECTS) & _NIST_TRNG_REG_SMODE_MAX_REJECTS_MASK) ++#define NIST_TRNG_REG_SMODE_GET_SECURE_EN(x) (((x) >> _NIST_TRNG_REG_SMODE_SECURE_EN) & _NIST_TRNG_REG_SMODE_SECURE_EN_MASK) ++#define NIST_TRNG_REG_SMODE_GET_NONCE(x) (((x) >> _NIST_TRNG_REG_SMODE_NONCE) & _NIST_TRNG_REG_SMODE_NONCE_MASK) ++ ++#define NIST_TRNG_REG_MODE_SET_SEC_ALG(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_SEC_ALG_MASK << _NIST_TRNG_REG_MODE_SEC_ALG)) | ((x) << _NIST_TRNG_REG_MODE_SEC_ALG)) ++#define NIST_TRNG_REG_MODE_SET_PRED_RESIST(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_PRED_RESIST_MASK << _NIST_TRNG_REG_MODE_PRED_RESIST)) | ((x) << _NIST_TRNG_REG_MODE_PRED_RESIST)) ++#define NIST_TRNG_REG_MODE_SET_ADDIN_PRESENT(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_ADDIN_PRESENT_MASK << _NIST_TRNG_REG_MODE_ADDIN_PRESENT)) | ((x) << _NIST_TRNG_REG_MODE_ADDIN_PRESENT)) ++#define NIST_TRNG_REG_MODE_SET_KAT_SEL(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_KAT_SEL_MASK << _NIST_TRNG_REG_MODE_KAT_SEL)) | ((x) << _NIST_TRNG_REG_MODE_KAT_SEL)) ++#define NIST_TRNG_REG_MODE_SET_KAT_VEC(y, x) (((y) & ~(_NIST_TRNG_REG_MODE_KAT_VEC_MASK << _NIST_TRNG_REG_MODE_KAT_VEC)) | ((x) << _NIST_TRNG_REG_MODE_KAT_VEC)) ++#define NIST_TRNG_REG_MODE_GET_SEC_ALG(x) (((x) >> _NIST_TRNG_REG_MODE_SEC_ALG) & _NIST_TRNG_REG_MODE_SEC_ALG_MASK) ++#define NIST_TRNG_REG_MODE_GET_PRED_RESIST(x) (((x) >> _NIST_TRNG_REG_MODE_PRED_RESIST) & _NIST_TRNG_REG_MODE_PRED_RESIST_MASK) ++#define NIST_TRNG_REG_MODE_GET_ADDIN_PRESENT(x) (((x) >> _NIST_TRNG_REG_MODE_ADDIN_PRESENT) & _NIST_TRNG_REG_MODE_ADDIN_PRESENT_MASK) ++#define NIST_TRNG_REG_STAT_GET_DRBG_STATE(x) (((x) >> _NIST_TRNG_REG_STAT_DRBG_STATE) & _NIST_TRNG_REG_STAT_DRBG_STATE_MASK) ++#define NIST_TRNG_REG_STAT_GET_SECURE(x) (((x) >> _NIST_TRNG_REG_STAT_SECURE) & _NIST_TRNG_REG_STAT_SECURE_MASK) ++#define NIST_TRNG_REG_STAT_GET_NONCE(x) (((x) >> _NIST_TRNG_REG_STAT_NONCE_MODE) & _NIST_TRNG_REG_STAT_NONCE_MASK) ++ ++#endif +diff --git a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h +--- a/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/include/nisttrng_private.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef NISTTRNG_PRIVATE_H ++#define NISTTRNG_PRIVATE_H ++ ++#include "elppdu.h" ++#include "nisttrng_hw.h" ++#include "nisttrng_common.h" ++ ++int nisttrng_wait_on_busy(struct nist_trng_state *state); ++int nisttrng_wait_on_done(struct nist_trng_state *state); ++int nisttrng_wait_on_noise_rdy(struct nist_trng_state *state); ++int nisttrng_get_alarms(struct nist_trng_state *state); ++int nisttrng_reset_state(struct nist_trng_state *state); ++ ++/* ---------- Reminders ---------- */ ++int nisttrng_reset_counters(struct nist_trng_state *state); ++int nisttrng_set_reminder_max_bits_per_req(struct nist_trng_state *state, unsigned long max_bits_per_req); ++int nisttrng_set_reminder_max_req_per_seed(struct nist_trng_state *state, unsigned long long max_req_per_seed); ++int nisttrng_check_seed_lifetime(struct nist_trng_state *state); ++ ++/* ---------- Set field APIs ---------- */ ++int nisttrng_set_sec_strength(struct nist_trng_state *state, int req_sec_strength); ++int nisttrng_set_addin_present(struct nist_trng_state *state, int addin_present); ++int nisttrng_set_pred_resist(struct nist_trng_state *state, int pred_resist); ++int nisttrng_set_secure_mode(struct nist_trng_state *state, int secure_mode); ++int nisttrng_set_nonce_mode(struct nist_trng_state *state, int nonce_mode); ++ ++/* ---------- Load data APIs ---------- */ ++int nisttrng_load_ps_addin(struct nist_trng_state *state, void *input_str); ++ ++/* ---------- Command APIs ---------- */ ++int nisttrng_get_entropy_input(struct nist_trng_state *state, void *input_nonce, int nonce_operation); ++int nisttrng_refresh_addin(struct nist_trng_state *state, void *addin_str); ++int nisttrng_gen_random(struct nist_trng_state *state, void *random_bits, unsigned long req_num_bytes); ++int nisttrng_advance_state(struct nist_trng_state *state); ++int nisttrng_kat(struct nist_trng_state *state, int kat_sel, int kat_vec); ++int nisttrng_full_kat(struct nist_trng_state *state); ++int nisttrng_zeroize(struct nist_trng_state *state); ++ ++/* ---------- edu related ---------- */ ++ ++int nisttrng_rnc(struct nist_trng_state *state, int rnc_ctrl_cmd); ++int nisttrng_wait_fifo_full(struct nist_trng_state *state); ++#endif +diff --git a/drivers/char/hw_random/dwc/src/trng/include/synversion.h b/drivers/char/hw_random/dwc/src/trng/include/synversion.h +--- a/drivers/char/hw_random/dwc/src/trng/include/synversion.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/include/synversion.h 2026-09-09 15:51:42.909265407 +0000 +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef VERSION_H ++#define VERSION_H ++ ++#define TRNG_VERSION "1.00a" ++ ++#endif +diff --git a/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c b/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c +--- a/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/kernel/nist_trng.c 2026-09-09 15:51:42.910265392 +0000 +@@ -0,0 +1,2170 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2017 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "nisttrng.h" ++ ++#define SYNOPSYS_HWRNG_DRIVER_NAME "hwrng-nist_trng" ++ ++#define num_gen_bytes 64 ++static unsigned long max_reads = 128; ++ ++struct synopsys_nisttrng_driver { ++ struct nist_trng_state nisttrng; ++ void *hwrng_drv; ++ void *crypto_drv; ++ unsigned char rand_out[num_gen_bytes]; ++}; ++ ++static unsigned int xxd_vtrng; ++ ++static void nisttrng_reinit(struct nist_trng_state *nist_trng) ++{ ++ int err; ++ ++ err = nisttrng_uninstantiate(nist_trng); ++ if (err && err != CRYPTO_NOT_INSTANTIATED) ++ goto ERR; ++ ++ err = nisttrng_instantiate(nist_trng, 128, 1, NULL); ++ if (err) ++ goto ERR; ++ ++ERR: ++ DEBUG("NIST_TRNG: Trying to reinitialize after a fatal alarm: %d\n", ++ err); ++} ++ ++static int nisttrng_platform_driver_read(struct platform_device *pdev, ++ void *buf, size_t max, bool wait) ++{ ++ struct synopsys_nisttrng_driver *data = 0; ++ int nisttrng_error = -1; ++ u32 *out = kmalloc(max, GFP_KERNEL); ++ unsigned int vtrng; ++ ++ if (!out) { ++ SYNHW_PRINT("memory not allocated\n"); ++ return -1; ++ } ++ ++ if (!pdev || !buf || !max) ++ return nisttrng_error; ++ ++ data = platform_get_drvdata(pdev); ++ if (data == 0) ++ return nisttrng_error; ++ ++ if (data->nisttrng.config.build_cfg0.edu_present) { ++ vtrng = xxd_vtrng % ((data->nisttrng.config.edu_build_cfg0 ++ .public_vtrng_channels) + ++ 1); ++ if (vtrng == 0) { ++ /* private vtrng */ ++ nisttrng_error = nisttrng_generate(&data->nisttrng, out, max, ++ data->nisttrng.status.sec_strength ? 256 : 128, ++ data->nisttrng.status.pred_resist, NULL); ++ } else { ++ /* public vtrng */ ++ nisttrng_error = nisttrng_generate_public_vtrng(&data->nisttrng, out, max, vtrng - 1); ++ } ++ xxd_vtrng++; ++ } else { ++ /* nist core vtrng */ ++ nisttrng_error = nisttrng_generate(&data->nisttrng, out, max, ++ data->nisttrng.status.sec_strength ? 256 : 128, ++ data->nisttrng.status.pred_resist, NULL); ++ } ++ if (nisttrng_error < 0) { ++ if (data->nisttrng.status.alarm_code) ++ nisttrng_reinit(&data->nisttrng); ++ ++ return nisttrng_error; ++ } ++ ++ memcpy(buf, out, max); ++ kfree(out); ++ ++ return max; ++} ++ ++static int nisttrng_hwrng_driver_read(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ struct platform_device *pdev = 0; ++ ++ if (rng == 0) ++ return -1; ++ ++ pdev = (struct platform_device *)rng->priv; ++ return nisttrng_platform_driver_read(pdev, buf, max, wait); ++} ++ ++static ssize_t ckr_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "rel_num=%u, ext_ver=%u, ext_enum=%u\n", ++ priv->nisttrng.config.corekit_rel.rel_num, ++ priv->nisttrng.config.corekit_rel.ext_ver, ++ priv->nisttrng.config.corekit_rel.ext_enum); ++} ++ ++static ssize_t features_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, ++ "drbg_arch = %u, diag_basic_trng=%u, diag_st_hlt=%u, diag_ns=%u, secure_rst_state=%u, extra_ps_present=%u\n", ++ priv->nisttrng.config.features.drbg_arch, ++ priv->nisttrng.config.features.diag_level_basic_trng, ++ priv->nisttrng.config.features.diag_level_stat_hlt, ++ priv->nisttrng.config.features.diag_level_ns, ++ priv->nisttrng.config.features.secure_rst_state, ++ priv->nisttrng.config.features.extra_ps_present); ++} ++ ++static ssize_t secure_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%s\n", NIST_TRNG_REG_SMODE_GET_SECURE_EN(pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_SMODE)) ? "on" : "off"); ++} ++ ++static ssize_t secure_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = nisttrng_set_secure_mode(&priv->nisttrng, ++ sysfs_streq(buf, "on") ? 1 : 0); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t nonce_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%s\n", NIST_TRNG_REG_SMODE_GET_NONCE(pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_SMODE)) ? "on" : "off"); ++} ++ ++static ssize_t nonce_store(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = nisttrng_set_nonce_mode(&priv->nisttrng, ++ sysfs_streq(buf, "on") ? 1 : 0); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t sec_strength_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%s\n", ++ priv->nisttrng.status.sec_strength ? "256" : "128"); ++} ++ ++static ssize_t sec_strength_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ int tmp; ++ int ret; ++ ++ if (count > 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtoint(foo, 10, &tmp); ++ if (ret) ++ return ret; ++ ++ ret = nisttrng_set_sec_strength(&priv->nisttrng, tmp); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t rand_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ unsigned int x; ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ for (x = 0; x < 4; x++) { ++ sprintf(buf + 8 * x, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_RAND0 + 3 - x)); ++ } ++ ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++static ssize_t seed_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ unsigned int x; ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ for (x = 0; x < 12; x++) { ++ sprintf(buf + 8 * x, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_SEED0 + 11 - x)); ++ } ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++static ssize_t seed_reg_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int x, tmp; ++ int ret; ++ ++ // string must be at least 12 32-bit words long in 0 padded hex ++ if (count < (2 * 12 * 4)) ++ return -1; ++ ++ foo[8] = 0; ++ for (x = 0; x < 12; x++) { ++ memcpy(foo, buf + x * 8, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SEED0 + x, ++ tmp); ++ } ++ ++ return count; ++} ++ ++static ssize_t npa_data_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ unsigned int x; ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ for (x = 0; x < 16; x++) { ++ sprintf(buf + 8 * x, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_NPA_DATA0 + 15 - x)); ++ } ++ ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++static ssize_t npa_data_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int x, tmp; ++ int ret; ++ ++ // string must be at least 16 32-bit words long in 0 padded hex ++ if (count < (2 * 16 * 4)) ++ return -1; ++ ++ foo[8] = 0; ++ for (x = 0; x < 16; x++) { ++ memcpy(foo, buf + x * 8, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_NPA_DATA0 + x, tmp); ++ } ++ ++ return count; ++} ++ ++static ssize_t ctrl_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_CTRL)); ++} ++ ++static ssize_t ctrl_reg_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_CTRL, tmp); ++ return count; ++} ++ ++static ssize_t istat_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ISTAT)); ++} ++ ++static ssize_t istat_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ISTAT, tmp); ++ return count; ++} ++ ++static ssize_t mode_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_MODE)); ++} ++ ++static ssize_t mode_reg_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_MODE, tmp); ++ ++ return count; ++} ++ ++static ssize_t smode_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_SMODE)); ++} ++ ++static ssize_t smode_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, tmp); ++ return count; ++} ++ ++static ssize_t alarm_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ALARM)); ++} ++ ++static ssize_t alarm_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ALARM, tmp); ++ return count; ++} ++ ++static ssize_t stat_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_STAT)); ++} ++ ++static ssize_t ia_wdata_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA, tmp); ++ return count; ++} ++ ++static ssize_t ia_wdata_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA)); ++} ++ ++static ssize_t ia_rdata_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_RDATA)); ++} ++ ++static ssize_t ia_addr_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, tmp); ++ return count; ++} ++ ++static ssize_t ia_addr_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR)); ++} ++ ++static ssize_t ia_cmd_reg_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, tmp); ++ return count; ++} ++ ++static ssize_t ia_cmd_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD)); ++} ++ ++static ssize_t rnc_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL)); ++} ++ ++static ssize_t rnc_reg_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned int tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL, tmp); ++ ++ return count; ++} ++ ++static ssize_t rbc_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RBC_CTRL)); ++} ++ ++static ssize_t rbc_reg_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ char opts_str[5]; ++ unsigned int opts_int; ++ int enable, rbc_num, rate, urun_blnk, ret; ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ opts_str[4] = 0; ++ memcpy(opts_str, buf, 4); ++ ret = kstrtouint(opts_str, 16, &opts_int); ++ if (ret) ++ return ret; ++ ++ SYNHW_PRINT("%s %x\n", __func__, opts_int); ++ ++ enable = (opts_int >> 12 & 0xf); ++ if (enable > 1) { ++ SYNHW_PRINT("incorrect enable %x\n", enable); ++ return -1; ++ } ++ ++ rbc_num = (opts_int >> 8 & 0xf); ++ if (rbc_num > priv->nisttrng.config.edu_build_cfg0.rbc_channels - 1) { ++ SYNHW_PRINT("incorrect rbc_num %x\n", rbc_num); ++ return -1; ++ } ++ ++ rate = (opts_int >> 4 & 0xf); ++ if (rate > 8) { ++ SYNHW_PRINT("incorrect rate %x\n", rate); ++ return -1; ++ } ++ ++ urun_blnk = (opts_int & 0xf); ++ if (urun_blnk > 3) { ++ SYNHW_PRINT("incorrect urun_blnk %x\n", urun_blnk); ++ return -1; ++ } ++ ++ SYNHW_PRINT("enable %x rbc_num %x rate %x urun_blnk %x\n", enable, ++ rbc_num, rate, urun_blnk); ++ ++ ret = nisttrng_rbc(&priv->nisttrng, enable, rbc_num, rate, ++ urun_blnk); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t hw_state_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ u32 addr; ++ int i; ++ int tot_char; ++ ++ addr = 0x20; ++ tot_char = sprintf(buf, "Key = "); ++ for (i = 0; i < 8; i++) { ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, ++ addr + 7 - i); ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, ++ 0x80000000); ++ tot_char += sprintf(buf + tot_char, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_IA_RDATA)); ++ } ++ tot_char += sprintf(buf + tot_char, "\n"); ++ ++ addr = 0x28; ++ tot_char += sprintf(buf + tot_char, "V = "); ++ for (i = 0; i < 4; i++) { ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, ++ addr + 3 - i); ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, ++ 0x80000000); ++ tot_char += sprintf(buf + tot_char, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_IA_RDATA)); ++ } ++ ++ tot_char += sprintf(buf + tot_char, "\n"); ++ ++ return tot_char; ++} ++ ++static ssize_t max_bits_per_req_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ unsigned long tmp; ++ int ret; ++ ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; ++ ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtoul(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ ret = nisttrng_set_reminder_max_bits_per_req(&priv->nisttrng, ++ tmp); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t max_bits_per_req_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08lx\n", ++ priv->nisttrng.counters.max_bits_per_req); ++} ++ ++static ssize_t max_req_per_seed_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[17]; ++ unsigned long long tmp; ++ int ret; ++ ++ // string must be at least a 64-bit word in 0 padded hex ++ if (count < 16) ++ return -1; ++ ++ foo[16] = 0; ++ memcpy(foo, buf, 16); ++ ret = kstrtoull(foo, 16, &tmp); ++ if (ret) ++ return ret; ++ ++ ret = nisttrng_set_reminder_max_req_per_seed(&priv->nisttrng, ++ tmp); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t max_req_per_seed_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%08llx\n", ++ priv->nisttrng.counters.max_req_per_seed); ++} ++ ++static ssize_t collect_ent_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ int rep; ++ int i, j; ++ int ret; ++ u32 tmp; ++ int t; ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ // Change to TEST mode ++ DEBUG("Change to TEST mode\n"); ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, 0x00000028); ++ // Turn on the noise collect mode ++ DEBUG("Turn on the noise collect mode\n"); ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, 0x80000028); ++ ++ // issue generate entropy command ++ DEBUG("Issue a GEN_NOISE command\n"); ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_GEN_NOISE); ++ ++ // read raw noise ++ // 2 reads if sec_strength is 128 and 3 reads if it is 256 ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ rep = 2; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ rep = 3; ++ ++ for (i = 0; i < rep; i++) { ++ t = NIST_TRNG_RETRY_MAX; ++ tmp = 0; ++ DEBUG("Wait for NOISE_RDY interrupt.\n"); ++ do { ++ tmp = pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_ISTAT); ++ } while (!(tmp & (NIST_TRNG_REG_ISTAT_NOISE_RDY | ++ NIST_TRNG_REG_ISTAT_ALARMS)) && ++ --t); ++ ++ DEBUG("Read NPA_DATAx\n"); ++ for (j = 0; j < 16; j++) { ++ sprintf(buf + 128 * i + 8 * j, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_NPA_DATA0 + j)); ++ } ++ ++ // clear NOISE_RDY IRQ ++ DEBUG("Clear NOISE_RDY interrupt.\n"); ++ ret = nisttrng_wait_on_noise_rdy(&priv->nisttrng); ++ if (ret) ++ return -1; ++ } ++ ++ DEBUG("Wait for DONE\n"); ++ ret = nisttrng_wait_on_done(&priv->nisttrng); ++ if (ret) ++ return -1; ++ ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++static ssize_t collect_ent_nsout_show(struct device *dev, ++ struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ int rep; ++ int i; ++ int ret; ++ ++ // generate entropy ++ ret = nisttrng_get_entropy_input(&priv->nisttrng, NULL, 0); ++ if (ret) ++ return -1; ++ ++ // read NS_OUTPUTx ++ // 32 reads if sec_strength is 128 and 48 reads if it is 256 ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ rep = 32; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ rep = 48; ++ ++ for (i = 0; i < rep; i++) { ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, ++ 0x70 + rep - 1 - i); ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, ++ 0x80000000); ++ sprintf(buf + 8 * i, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_IA_RDATA)); ++ } ++ ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++static ssize_t nonce_seed_with_df_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ u32 seed[48] = { 0 }; ++ int rep; ++ int i; ++ int ret; ++ ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ rep = 2; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ rep = 3; ++ ++ DEBUG("Number of char in input = %zu\n", count); ++ if (count != (rep * 128)) ++ return -1; ++ ++ foo[8] = 0; ++ for (i = 0; i < (rep * 16); i++) { ++ memcpy(foo, buf + i * 8, 8); ++ ret = kstrtouint(foo, 16, (seed + (rep * 16 - 1) - i)); ++ if (ret) ++ return ret; ++ } ++ ++ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 1); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t nonce_seed_direct_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char foo[9]; ++ u32 seed[12] = { 0 }; ++ int rep; ++ int i; ++ int ret; ++ ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ rep = 2; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ rep = 3; ++ ++ DEBUG("Number of char in input = %zu\n", count); ++ if (count != (rep * 32)) ++ return -1; ++ ++ foo[8] = 0; ++ for (i = 0; i < (rep * 4); i++) { ++ memcpy(foo, buf + i * 8, 8); ++ ret = kstrtouint(foo, 16, (seed + (rep * 4 - 1) - i)); ++ if (ret) ++ return ret; ++ } ++ ++ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 0); ++ if (ret) ++ return -1; ++ ++ return count; ++} ++ ++static ssize_t instantiate_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char opts_str[101]; ++ unsigned int opts_int; ++ int req_sec_strength = 256; ++ int pred_resist = 1; ++ bool ps_exists = 0; ++ u32 ps[12]; ++ unsigned int ps_length; ++ int i; ++ int ret; ++ ++ /* First 3 digits: ++ * they have to be 0 or 1 ++ * 2-1-0 --> 2: predictoin resistance, 1: security strength, 0: personilizatoin string existence ++ */ ++ opts_str[3] = 0; ++ memcpy(opts_str, buf, 3); ++ ret = kstrtouint(opts_str, 2, &opts_int); ++ if (ret) ++ return ret; ++ ++ if (((opts_str[0] != '0') && (opts_str[0] != '1')) || ++ ((opts_str[1] != '0') && (opts_str[1] != '1')) || ++ ((opts_str[2] != '0') && (opts_str[2] != '1'))) { ++ SYNHW_PRINT("Invalid input options: First 3 digits can only be 1 or 0\n"); ++ return -1; ++ } ++ ++ if (opts_int & 1) ++ ps_exists = 1; ++ else ++ ps_exists = 0; ++ ++ if (opts_int & 2) ++ req_sec_strength = 256; ++ else ++ req_sec_strength = 128; ++ ++ if (opts_int & 4) ++ pred_resist = 1; ++ else ++ pred_resist = 0; ++ ++ /* check input option length */ ++ if (!ps_exists) { ++ if (count != 3) { ++ SYNHW_PRINT("Invalid input options: If personilization string does not exist, options has to be 3 char.\n"); ++ return -1; ++ } ++ } else { ++ if (req_sec_strength == 128) { ++ if (count != 64 + 4) { // +4 for options and "-" ++ SYNHW_PRINT("Invalid input options: If personilization string exists and security strength is 128-bit, options has to be 68 char (not %zu char).\n", ++ count); ++ return -1; ++ } ++ } else if (req_sec_strength == 256) { ++ if (count != ++ 96 + 4) { // +4 for options and "-", +1 because of the termination char that count includes ++ SYNHW_PRINT("Invalid input options: If personilization string exists and security strength is 256-bit, options has to be 100 char (not %zu char).\n", ++ count); ++ return -1; ++ } ++ } else { ++ SYNHW_PRINT("Invalid input options\n"); ++ return -1; ++ } ++ } ++ ++ /* Personilization string */ ++ for (i = 0; i < 12; i++) ++ ps[i] = 0; ++ ++ if (req_sec_strength == 128) ++ ps_length = 64; ++ else if (req_sec_strength == 256) ++ ps_length = 96; ++ else ++ SYNHW_PRINT("Invalid security strength\n"); ++ ++ if (ps_exists) { ++ opts_str[1] = 0; ++ memcpy(opts_str, buf + 3, 1); ++ ++ if (opts_str[0] == '-') { ++ opts_str[8] = 0; ++ for (i = 0; i < ps_length / 8; i++) { ++ memcpy(opts_str, buf + 4 + i * 8, 8); ++ ret = kstrtouint(opts_str, 16, ++ ps + (ps_length / 8 - 1) - i); ++ if (ret) ++ return ret; ++ } ++ } else { ++ SYNHW_PRINT("4th character of input has to be \"-\" when personilization string exists\n"); ++ } ++ ++ ret = nisttrng_instantiate(&priv->nisttrng, ++ req_sec_strength, pred_resist, ++ ps); ++ if (ret) ++ return -1; ++ ++ } else { ++ ret = nisttrng_instantiate(&priv->nisttrng, ++ req_sec_strength, pred_resist, ++ NULL); ++ if (ret) ++ return -1; ++ } ++ ++ return count; ++} ++ ++static ssize_t uninstantiate_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ ++ nisttrng_uninstantiate(&priv->nisttrng); ++ ++ return count; ++} ++ ++static ssize_t reseed_store(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char opts_str[100]; ++ unsigned int opts_int; ++ int pred_resist = 1; ++ bool addin_exists = 0; ++ u32 addin[12]; ++ unsigned int addin_length; ++ int i; ++ int ret; ++ ++ /* First 2 digits: ++ * they have to be 0 or 1 ++ * 1-0 --> 1: predictoin resistance, 0: additional input string existence ++ */ ++ opts_str[2] = 0; ++ memcpy(opts_str, buf, 2); ++ ret = kstrtouint(opts_str, 2, &opts_int); ++ if (ret) ++ return ret; ++ ++ if (((opts_str[0] != '0') && (opts_str[0] != '1')) || ++ ((opts_str[1] != '0') && (opts_str[1] != '1'))) { ++ SYNHW_PRINT("Invalid input options: First 2 digits can only be 1 or 0\n"); ++ return -1; ++ } ++ ++ if (opts_int & 1) ++ addin_exists = 1; ++ else ++ addin_exists = 0; ++ ++ if (opts_int & 2) ++ pred_resist = 1; ++ else ++ pred_resist = 0; ++ ++ /* check input option length */ ++ if (!addin_exists) { ++ if (count != 2) { ++ SYNHW_PRINT("Invalid input options: If additional input does not exist, options has to be 2 char.\n"); ++ return -1; ++ } ++ } else { ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) { ++ if (count != 64 + 3) { // +3 for options and "-" ++ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 128-bit, options has to be 67 char.\n"); ++ return -1; ++ } ++ } else if (priv->nisttrng.status.sec_strength == ++ SEC_STRNT_AES256) { ++ if (count != 96 + 3) { // +3 for options and "-" ++ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 256-bit, options has to be 99 char.\n"); ++ return -1; ++ } ++ } else { ++ SYNHW_PRINT("Invalid input options\n"); ++ return -1; ++ } ++ } ++ ++ /* Additional input */ ++ for (i = 0; i < 12; i++) ++ addin[i] = 0; ++ ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ addin_length = 64; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ addin_length = 96; ++ else ++ SYNHW_PRINT("Invalid security strength\n"); ++ ++ if (addin_exists) { ++ opts_str[1] = 0; ++ memcpy(opts_str, buf + 2, 1); ++ ++ if (opts_str[0] == '-') { ++ opts_str[8] = 0; ++ for (i = 0; i < addin_length / 8; i++) { ++ memcpy(opts_str, buf + 3 + i * 8, 8); ++ ret = kstrtouint(opts_str, 16, addin + (addin_length / 8 - 1) - i); ++ if (ret) ++ return ret; ++ } ++ } else { ++ SYNHW_PRINT("3rd character of input has to be \"-\" when additional input exists\n"); ++ } ++ ++ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, ++ addin); ++ if (ret) ++ return -1; ++ ++ } else { ++ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, ++ NULL); ++ if (ret) ++ return -1; ++ } ++ ++ return count; ++} ++ ++static ssize_t generate_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char opts_str[101]; ++ unsigned int opts_int; ++ int req_sec_strength = 128; ++ int pred_resist = 1; ++ bool addin_exists = 0; ++ unsigned char out[num_gen_bytes]; ++ u32 addin[12]; ++ unsigned int addin_length; ++ int i; ++ int ret; ++ ++ /* First 3 digits: ++ * they have to be 0 or 1 ++ * 2-1-0 --> 2: predictoin resistance, 1: security strength, 0: additional input string existence ++ */ ++ opts_str[3] = 0; ++ memcpy(opts_str, buf, 3); ++ ret = kstrtouint(opts_str, 2, &opts_int); ++ if (ret) ++ return ret; ++ ++ if (((opts_str[0] != '0') && (opts_str[0] != '1')) || ++ ((opts_str[1] != '0') && (opts_str[1] != '1')) || ++ ((opts_str[2] != '0') && (opts_str[2] != '1'))) { ++ SYNHW_PRINT("Invalid input options: First 3 digits can only be 1 or 0\n"); ++ return -1; ++ } ++ ++ if (opts_int & 1) ++ addin_exists = 1; ++ else ++ addin_exists = 0; ++ ++ if (opts_int & 2) ++ req_sec_strength = 256; ++ else ++ req_sec_strength = 128; ++ ++ if (opts_int & 4) ++ pred_resist = 1; ++ else ++ pred_resist = 0; ++ ++ /* check input option length */ ++ if (!addin_exists) { ++ if (count != 3) { ++ SYNHW_PRINT("Invalid input options: If additional input does not exist, options has to be 3 char.\n"); ++ return -1; ++ } ++ } else { ++ if (req_sec_strength == 128) { ++ if (count != 64 + 4) { // +4 for options and "-" ++ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 128-bit, options has to be 68 char.\n"); ++ return -1; ++ } ++ } else if (req_sec_strength == 256) { ++ if (count != 96 + 4) { // +4 for options and "-" ++ SYNHW_PRINT("Invalid input options: If additional input exists and security strength is 256-bit, options has to be 100 char.\n"); ++ return -1; ++ } ++ } else { ++ SYNHW_PRINT("Invalid input options\n"); ++ return -1; ++ } ++ } ++ ++ /* Additional input */ ++ for (i = 0; i < 12; i++) ++ addin[i] = 0; ++ ++ if (req_sec_strength == 128) ++ addin_length = 64; ++ else if (req_sec_strength == 256) ++ addin_length = 96; ++ else ++ SYNHW_PRINT("Invalid security strength\n"); ++ ++ if (addin_exists) { ++ opts_str[1] = 0; ++ memcpy(opts_str, buf + 3, 1); ++ ++ if (opts_str[0] == '-') { ++ opts_str[8] = 0; ++ for (i = 0; i < addin_length / 8; i++) { ++ memcpy(opts_str, buf + 4 + i * 8, 8); ++ ret = kstrtouint(opts_str, 16, addin + (addin_length / 8 - 1) - i); ++ if (ret) ++ return ret; ++ } ++ } else { ++ SYNHW_PRINT("4th character of input has to be \"-\" when additional input exists\n"); ++ } ++ ++ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, ++ num_gen_bytes, req_sec_strength, ++ pred_resist, addin); ++ if (ret) ++ return -1; ++ ++ } else { ++ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, ++ num_gen_bytes, req_sec_strength, ++ pred_resist, NULL); ++ if (ret) ++ return -1; ++ } ++ ++ /* store the result */ ++ memcpy(priv->rand_out, out, sizeof(out)); ++ ++ return count; ++} ++ ++static ssize_t generate_pub_vtrng_store(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ char opts_str[2]; ++ unsigned int opts_int; ++ unsigned char out[num_gen_bytes]; ++ int ret; ++ ++ opts_str[1] = 0; ++ memcpy(opts_str, buf, 1); ++ ret = kstrtouint(opts_str, 16, &opts_int); ++ if (ret) ++ return ret; ++ ++ SYNHW_PRINT("%s %d %d %d %d\n", __func__, opts_str[0], ++ priv->nisttrng.config.edu_build_cfg0.public_vtrng_channels, ++ opts_str[1], opts_int); ++ ++ ret = nisttrng_generate_public_vtrng(&priv->nisttrng, ++ (u32 *)out, ++ num_gen_bytes, opts_int); ++ if (ret) ++ return -1; ++ ++ memcpy(priv->rand_out, out, sizeof(out)); ++ ++ return count; ++} ++ ++/* rand_out_show displays last generated random number (num_gen_bytes number of bytes), not just the last block. */ ++static ssize_t rand_out_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ unsigned int i, j; ++ unsigned long rand; ++ bool all_zero = true; ++ ++ /* If all bits of the rand_reg register are 0, display 0 */ ++ for (i = 0; i < 4; i++) { ++ rand = pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_RAND0 + ++ (3 - i)); ++ if (rand != 0) { ++ all_zero = false; ++ break; ++ } ++ } ++ ++ if (all_zero) { ++ sprintf(buf + 2 * i, "%02x", 0); ++ } else { ++ for (i = 0; i < (num_gen_bytes / 16); i++) { ++ for (j = 0; j < 16; j++) { ++ sprintf(buf + 2 * (i * 16 + j), "%02x", ++ priv->rand_out[(i + 1) * 16 - 1 - j]); ++ } ++ } ++ j = 0; ++ while (i * 16 + j < num_gen_bytes) { ++ sprintf(buf + 2 * (i * 16 + j), "%02x", ++ priv->rand_out[num_gen_bytes - 1 - j]); ++ j++; ++ } ++ } ++ ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++/* rand_out_vtrng_show displays last generated random number (num_gen_bytes number of bytes), not just the last block. */ ++static ssize_t rand_out_vtrng_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ unsigned int i, j; ++ ++ /* If all bits of the rand_reg register are 0, display 0 */ ++ ++ for (i = 0; i < (num_gen_bytes / 16); i++) { ++ for (j = 0; j < 16; j++) { ++ sprintf(buf + 2 * (i * 16 + j), "%02x", ++ priv->rand_out[(i + 1) * 16 - 1 - j]); ++ } ++ } ++ ++ j = 0; ++ while (i * 16 + j < num_gen_bytes) { ++ sprintf(buf + 2 * (i * 16 + j), "%02x", ++ priv->rand_out[num_gen_bytes - 1 - j]); ++ j++; ++ } ++ ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++static ssize_t kat_store(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ if (sysfs_streq(buf, "full")) { ++ ret = nisttrng_full_kat(&priv->nisttrng); ++ if (ret) ++ return -1; ++ ++ } else if (sysfs_streq(buf, "00")) { ++ ret = nisttrng_kat(&priv->nisttrng, 0, 0); ++ if (ret) ++ return -1; ++ ++ } else if (sysfs_streq(buf, "01")) { ++ ret = nisttrng_kat(&priv->nisttrng, 0, 1); ++ if (ret) ++ return -1; ++ ++ } else if (sysfs_streq(buf, "10")) { ++ ret = nisttrng_kat(&priv->nisttrng, 1, 0); ++ if (ret) ++ return -1; ++ ++ } else if (sysfs_streq(buf, "11")) { ++ ret = nisttrng_kat(&priv->nisttrng, 1, 1); ++ if (ret) ++ return -1; ++ ++ } else { ++ ret = nisttrng_full_kat(&priv->nisttrng); ++ if (ret) ++ return -1; ++ } ++ ++ return count; ++} ++ ++static void str_to_384_bit(char *buf, u32 *out) ++{ ++ char foo[9]; ++ int i; ++ int ret; ++ ++ foo[8] = 0; ++ for (i = 0; i < 12; i++) { ++ memcpy(foo, buf + i * 8, 8); ++ ret = kstrtouint(foo, 16, out + 11 - i); ++ } ++} ++ ++/* This attribute is only for test purpuses */ ++static ssize_t test_attr_store(struct device *dev, ++ struct device_attribute *devattr, const char *buf, ++ size_t count) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ int i; ++ int err; ++ u32 addin[12]; ++ u32 ps[12]; ++ char *out; ++ ++ char buf_seed1[96] = ++ "c54805274bde00aa5289e0513579019707666d2fa7a1c8908865891c87c0c652335a4d3cc415bc30742b164647f8820f"; ++ char buf_ps1[96] = ++ "d63fb5afa2101fa4b8a6c3b89d9c250ac728fc1ddad0e7585b5d54728ed20c2f940e89155596e3b963635b6d6088164b"; ++ char buf_addin1[96] = ++ "744bfae3c23a5cc9a3b373b6c50795068d35eb8a339746ac810d16f864e880061082edf9d2687c211960aa83400f85f9"; ++ char buf_seed2[96] = ++ "b2ad31d1f20dcf30dd526ec9156c07f270216bdb59197325bab180675929888ab699c54fb21819b7d921d6346bff2f7f"; ++ char buf_addin2[96] = ++ "ad55c682962aa4fe9ebc227c9402e79b0aa7874844d33eaee7e2d15baf81d9d33936e4d93f28ad109657b512aee115a5"; ++ char buf_seed3[96] = ++ "eca449048d26fd38f8ca435237dce66eadec7069ee5dd0b70084b819a711c0820a7556bbd0ae20f06e5169278b593b71"; ++ u32 tmp[12]; ++ ++ for (i = 0; i < 12; i++) ++ addin[i] = i; ++ ++ for (i = 0; i < 12; i++) ++ ps[i] = i + 100; ++ ++ /* SDK doc example - Prediction Resistance not available, no Reseed */ ++ err = nisttrng_uninstantiate(&priv->nisttrng); ++ if (err && err != CRYPTO_NOT_INSTANTIATED) ++ return -1; ++ ++ if (nisttrng_instantiate(&priv->nisttrng, 128, 0, ps) < 0) ++ return -1; ++ ++ out = kmalloc(10, GFP_KERNEL); ++ if (nisttrng_generate(&priv->nisttrng, out, 10, 128, 0, addin) < 0) ++ return -1; ++ ++ DEBUG("----- Generate 10 bytes\n"); ++ for (i = 0; i < 10; i++) ++ DEBUG("%02x", out[i]); ++ ++ DEBUG("\n"); ++ kfree(out); ++ ++ out = kmalloc(512, GFP_KERNEL); ++ if (nisttrng_generate(&priv->nisttrng, out, 512, 128, 0, addin) < 0) ++ return -1; ++ ++ DEBUG("----- Generate 512 bytes\n"); ++ for (i = 0; i < 512; i++) ++ DEBUG("%02x", out[i]); ++ ++ DEBUG("\n"); ++ kfree(out); ++ ++ out = kmalloc(41, GFP_KERNEL); ++ if (nisttrng_generate(&priv->nisttrng, out, 41, 128, 0, addin) < 0) ++ return -1; ++ ++ DEBUG("----- Generate 41 bytes\n"); ++ for (i = 0; i < 41; i++) ++ DEBUG("%02x", out[i]); ++ ++ DEBUG("\n"); ++ kfree(out); ++ ++ err = nisttrng_uninstantiate(&priv->nisttrng); ++ if (err < 0 && err != CRYPTO_NOT_INSTANTIATED) ++ return -1; ++ ++ /* SDK doc example - DRBG Validation */ ++ err = nisttrng_uninstantiate(&priv->nisttrng); ++ if (err && err != CRYPTO_NOT_INSTANTIATED) ++ return -1; ++ ++ if (nisttrng_set_nonce_mode(&priv->nisttrng, 1) < 0) ++ return -1; ++ ++ out = kmalloc(64, GFP_KERNEL); ++ str_to_384_bit(buf_seed1, tmp); ++ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) ++ return -1; ++ ++ str_to_384_bit(buf_ps1, tmp); ++ if (nisttrng_instantiate(&priv->nisttrng, 256, 1, tmp) < 0) ++ return -1; ++ ++ str_to_384_bit(buf_seed2, tmp); ++ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) ++ return -1; ++ ++ str_to_384_bit(buf_addin1, tmp); ++ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) ++ return -1; ++ ++ str_to_384_bit(buf_seed3, tmp); ++ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) ++ return -1; ++ ++ str_to_384_bit(buf_addin2, tmp); ++ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) ++ return -1; ++ ++ memcpy(priv->rand_out, out, 64); ++ ++ return count; ++} ++ ++static DEVICE_ATTR_RO(ckr); ++static DEVICE_ATTR_RO(features); ++static DEVICE_ATTR_RW(secure); ++static DEVICE_ATTR_RW(nonce); ++static DEVICE_ATTR_RW(sec_strength); ++ ++static DEVICE_ATTR_RW(mode_reg); ++static DEVICE_ATTR_RW(smode_reg); ++static DEVICE_ATTR_RW(alarm_reg); ++static DEVICE_ATTR_RO(rand_reg); ++static DEVICE_ATTR_RO(rand_out); ++static DEVICE_ATTR_RO(rand_out_vtrng); ++static DEVICE_ATTR_RW(seed_reg); ++static DEVICE_ATTR_RW(npa_data_reg); ++static DEVICE_ATTR_RW(ctrl_reg); ++static DEVICE_ATTR_RW(istat_reg); ++static DEVICE_ATTR_RO(stat_reg); ++static DEVICE_ATTR_RW(rnc_reg); ++static DEVICE_ATTR_RW(rbc_reg); ++ ++static DEVICE_ATTR_RW(ia_wdata_reg); ++static DEVICE_ATTR_RO(ia_rdata_reg); ++static DEVICE_ATTR_RW(ia_addr_reg); ++static DEVICE_ATTR_RW(ia_cmd_reg); ++static DEVICE_ATTR_RO(hw_state); ++ ++static DEVICE_ATTR_RO(collect_ent); ++static DEVICE_ATTR_RO(collect_ent_nsout); ++static DEVICE_ATTR_WO(nonce_seed_with_df); ++static DEVICE_ATTR_WO(nonce_seed_direct); ++static DEVICE_ATTR_WO(instantiate); ++static DEVICE_ATTR_WO(uninstantiate); ++static DEVICE_ATTR_WO(reseed); ++static DEVICE_ATTR_WO(generate); ++static DEVICE_ATTR_WO(generate_pub_vtrng); ++static DEVICE_ATTR_WO(kat); ++ ++static DEVICE_ATTR_RW(max_bits_per_req); ++static DEVICE_ATTR_RW(max_req_per_seed); ++ ++static DEVICE_ATTR_WO(test_attr); ++ ++static const struct attribute_group nisttrng_attr_group = { ++ .attrs = ++ (struct attribute *[]){ ++ &dev_attr_ckr.attr, ++ //&dev_attr_stepping.attr, ++ &dev_attr_features.attr, &dev_attr_secure.attr, ++ &dev_attr_nonce.attr, &dev_attr_sec_strength.attr, ++ ++ &dev_attr_mode_reg.attr, &dev_attr_smode_reg.attr, ++ &dev_attr_alarm_reg.attr, &dev_attr_rand_reg.attr, ++ &dev_attr_rand_out.attr, &dev_attr_rand_out_vtrng.attr, ++ &dev_attr_seed_reg.attr, &dev_attr_npa_data_reg.attr, ++ &dev_attr_ctrl_reg.attr, &dev_attr_istat_reg.attr, ++ &dev_attr_stat_reg.attr, &dev_attr_rnc_reg.attr, ++ &dev_attr_rbc_reg.attr, ++ ++ &dev_attr_ia_wdata_reg.attr, ++ &dev_attr_ia_rdata_reg.attr, &dev_attr_ia_addr_reg.attr, ++ &dev_attr_ia_cmd_reg.attr, &dev_attr_hw_state.attr, ++ ++ &dev_attr_collect_ent.attr, ++ &dev_attr_collect_ent_nsout.attr, ++ &dev_attr_nonce_seed_with_df.attr, ++ &dev_attr_nonce_seed_direct.attr, ++ &dev_attr_instantiate.attr, ++ &dev_attr_uninstantiate.attr, &dev_attr_reseed.attr, ++ &dev_attr_generate.attr, ++ &dev_attr_generate_pub_vtrng.attr, &dev_attr_kat.attr, ++ ++ &dev_attr_max_bits_per_req.attr, ++ &dev_attr_max_req_per_seed.attr, ++ ++ &dev_attr_test_attr.attr, NULL }, ++}; ++ ++static int nisttrng_self_test(struct nist_trng_state *nist_trng) ++{ ++ u32 seed[16], out[4], x, y; ++ ++ static const u32 exp128[10][4] = { ++ { 0x5db79bb2, 0xc3a0df1e, 0x099482b6, ++ 0xc319981e }, // The 1st generated output ++ { 0xb344d301, 0xdbd97ca0, 0x6e66e668, ++ 0x0bcd4625 }, // The 2nd generate output ++ { 0xec553f18, 0xa0e5c3cb, 0x752c03c2, ++ 0x5e7b04f7 }, // The 3rd generate output ++ { 0xcfe23e6e, 0x5302edc2, 0xdbf7b05b, ++ 0x2c817c0f }, // The 4th generate output ++ { 0xbd5a8726, 0x028c43d0, 0xb77ac4e3, ++ 0x0844ba2c }, // The 5th generate output ++ { 0xa63b4c0e, 0x8d11d0ba, 0x08b5a10f, ++ 0xab731aff }, // The 6th generate output ++ { 0xb7b56a2f, 0x1d84d1f0, 0xe48d1a0a, ++ 0x43a010a6 }, // The 7th generate output ++ { 0xcf66439d, 0xc937451d, 0x75c34d20, ++ 0x21a21398 }, // The 8th generate output ++ { 0xcb6f0a57, 0x5ff34705, 0x08838e49, ++ 0x21137614 }, // The 9th generate output ++ { 0x61c48b24, 0x25c18d29, 0xc6005e4e, ++ 0xae3b0389 }, // The 10th generate output ++ }; ++ ++ static const u32 exp256[10][4] = { ++ { 0x1f1a1441, 0xa0865ece, 0x9ff8d5b9, ++ 0x3f78ace6 }, // The 1st generated output ++ { 0xf8190a86, 0x6d6ded2a, 0xc4d0e9bf, ++ 0x24dab55c }, // The 2nd generate output ++ { 0xd3948b74, 0x3dfea516, 0x9c3b86a2, ++ 0xeb184b41 }, // The 3rd generate output ++ { 0x2eb82ab6, 0x2aceefda, 0xc0cf6a5f, ++ 0xa45cb333 }, // The 4th generate output ++ { 0xa49b1c7b, 0x5b51bac7, 0x7586770b, ++ 0x8cb2c392 }, // The 5th generate output ++ { 0x3f3ba09d, 0xa2c9ad29, 0x9687fb8f, ++ 0xa5ae3fd5 }, // The 6th generate output ++ { 0x11dd1076, 0xe37e86cb, 0xced0220a, ++ 0x00448c4f }, // The 7th generate output ++ { 0x955a5e52, 0x84ee38b1, 0xb3271e5f, ++ 0x097751e3 }, // The 8th generate output ++ { 0x5cd73ba8, 0xd8a36a1e, 0xa8a2d7c3, ++ 0xa96de048 }, // The 9th generate output ++ { 0xfb374c63, 0x827b85fa, 0x244e0c7a, ++ 0xa09afd39 }, // The 10th generate output ++ }; ++ ++ int ret, enable, rate, urun; ++ u32 tmp; ++ ++ for (x = 0; x < 16; x++) ++ seed[x] = 0x12345679 * (x + 1); ++ ++ DEBUG("Doing a self-test with security strength of 128\n"); ++ ret = nisttrng_uninstantiate(nist_trng); ++ if (ret && ret != CRYPTO_NOT_INSTANTIATED) ++ goto ERR; ++ ++ //if ((ret = nisttrng_set_secure_mode(nist_trng, 0))) { goto ERR; } ++ ret = nisttrng_set_nonce_mode(nist_trng, 1); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_set_sec_strength(nist_trng, 128); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_instantiate(nist_trng, 128, 0, NULL); ++ if (ret) ++ goto ERR; ++ ++ if (nist_trng->config.build_cfg0.edu_present) { ++ ret = nisttrng_wait_fifo_full(nist_trng); ++ if (ret) ++ goto ERR; ++ } ++ ++ ret = nisttrng_generate(nist_trng, out, 16, 128, 0, NULL); ++ if (ret) ++ goto ERR; ++ ++ if (nist_trng->config.features.extra_ps_present) { ++ DEBUG("skip KAT with extra_ps_present\n"); ++ } else { ++ DEBUG("nist_trng: AES-128 Self-test output: "); ++ for (x = 0; x < 4; x++) ++ DEBUG("0x%08lx ", (unsigned long)out[x]); ++ ++ if (nist_trng->config.build_cfg0.edu_present) { ++ if (nist_trng->config.edu_build_cfg0 ++ .esm_channel) { //if esm_channel is available the first random number goes to esm ++ for (x = 0; x < 4; x++) { ++ if (out[x] != exp128[1][x]) ++ ret = 1; ++ } ++ } ++ } else { ++ for (x = 0; x < 4; x++) { ++ if (out[x] != exp128[0][x]) ++ ret = 1; ++ } ++ } ++ ++ if (ret) { ++ SYNHW_PRINT("... FAILED comparison\n"); ++ ret = -1; ++ goto ERR; ++ } else { ++ DEBUG("... PASSED\n"); ++ } ++ } ++ ++ // if edu is available check all the pvtrng's ++ if (nist_trng->config.build_cfg0.edu_present) { ++ for (x = 0; ++ x < nist_trng->config.edu_build_cfg0.public_vtrng_channels; ++ x++) { ++ DEBUG("vtrng %d\n", x); ++ ret = nisttrng_generate_public_vtrng(nist_trng, out, 16, x); ++ if (ret) ++ goto ERR; ++ ++ for (y = 0; y < 4; y++) { ++ DEBUG("0x%08lx ", (unsigned long)out[y]); ++ if (out[y] != exp128[x + 2][y]) ++ ret = 1; ++ } ++ if (ret) { ++ SYNHW_PRINT("... FAILED comparison\n"); ++ ret = -1; ++ goto ERR; ++ } else { ++ DEBUG("... PASSED\n"); ++ } ++ } ++ } ++ // if edu is available empty the fifo before creating the new instance with strength of 256 ++ if (nist_trng->config.build_cfg0.edu_present) { ++ nisttrng_rnc(nist_trng, ++ NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE); ++ tmp = NIST_TRNG_REG_ISTAT_DONE; ++ //always clear the busy bit after disabling RNC ++ pdu_io_write32(nist_trng->base + NIST_TRNG_REG_ISTAT, tmp); ++ tmp = pdu_io_read32(nist_trng->base + NIST_TRNG_REG_ISTAT); ++ do { ++ ret = nisttrng_generate_public_vtrng(nist_trng, out, 16, 0); ++ if (ret) ++ goto ERR; ++ ++ tmp = pdu_io_read32(nist_trng->base + ++ NIST_TRNG_EDU_STAT); ++ ++ } while (!NIST_TRNG_EDU_STAT_FIFO_EMPTY(tmp)); ++ } ++ ++ if (nist_trng->config.features.drbg_arch == AES256) { ++ // test AES-256 mode ++ DEBUG("Doing a self-test with security strength of 256\n"); ++ ret = nisttrng_uninstantiate(nist_trng); ++ if (ret && ret != CRYPTO_NOT_INSTANTIATED) ++ goto ERR; ++ ++ ret = nisttrng_set_nonce_mode(nist_trng, 1); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_set_sec_strength(nist_trng, 256); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_instantiate(nist_trng, 256, 0, NULL); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_generate(nist_trng, out, 16, 256, 0, NULL); ++ if (ret) ++ goto ERR; ++ ++ if (nist_trng->config.features.extra_ps_present) { ++ DEBUG("skip KAT with extra_ps_present\n"); ++ } else { ++ DEBUG("nist_trng: AES-256 Self-test output: "); ++ for (x = 0; x < 4; x++) ++ DEBUG("0x%08lx ", (unsigned long)out[x]); ++ ++ for (x = 0; x < 4; x++) { ++ if (out[x] != exp256[0][x]) ++ ret = 1; ++ } ++ if (ret) { ++ SYNHW_PRINT("... FAILED comparison\n"); ++ ret = -1; ++ goto ERR; ++ } else { ++ DEBUG("... PASSED\n"); ++ } ++ } ++ } ++ ++ // if edu is available check all the pvtrng's ++ if (nist_trng->config.build_cfg0.edu_present) { ++ for (x = 0; ++ x < nist_trng->config.edu_build_cfg0.public_vtrng_channels; ++ x++) { ++ DEBUG("vtrng 256 %d\n", x); ++ ret = nisttrng_generate_public_vtrng(nist_trng, out, 16, x); ++ if (ret) ++ goto ERR; ++ ++ for (y = 0; y < 4; y++) { ++ DEBUG("0x%08lx ", (unsigned long)out[y]); ++ if (out[y] != exp256[x + 1][y]) ++ ret = 1; ++ } ++ if (ret) { ++ SYNHW_PRINT("... FAILED comparison\n"); ++ ret = -1; ++ goto ERR; ++ } else { ++ DEBUG("... PASSED\n"); ++ } ++ } ++ ++ //Test RBC channels ++ // enable RBC channels with rate of 2 and urun 1 ++ enable = 1; ++ rate = 2; ++ urun = 1; ++ for (x = 0; x < nist_trng->config.edu_build_cfg0.rbc_channels; ++ x++) { ++ ret = nisttrng_rbc(nist_trng, enable, x, rate, urun); ++ if (ret) ++ goto ERR; ++ ++ tmp = pdu_io_read32(nist_trng->base + ++ NIST_TRNG_EDU_RBC_CTRL); ++ ++ switch (x) { ++ case 0: ++ if (rate != NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH0_RATE) || ++ urun != NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH0_URUN_BLANK)) { ++ goto ERR; ++ } ++ break; ++ case 1: ++ if (rate != NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH1_RATE) || ++ urun != NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH1_URUN_BLANK)) { ++ goto ERR; ++ } ++ break; ++ case 2: ++ if (rate != NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH2_RATE) || ++ urun != NISTTRNG_EDU_RBC_CTRL_GET_CH_URUN_BLANK(tmp, _NIST_TRNG_EDU_RBC_CTRL_CH2_URUN_BLANK)) { ++ goto ERR; ++ } ++ break; ++ default: ++ DEBUG("Incorrect rbc_num = %d\n", x); ++ goto ERR; ++ } ++ } ++ DEBUG("RBC test passed\n"); ++ } ++ ++ //IF RNCis not disable, disable it ++ if (pdu_io_read32(nist_trng->base + NIST_TRNG_EDU_RNC_CTRL) != ++ NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE) { ++ nisttrng_rnc(nist_trng, ++ NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE); ++ tmp = NIST_TRNG_REG_ISTAT_DONE; ++ //always clear the busy bit after disabling RNC ++ pdu_io_write32(nist_trng->base + NIST_TRNG_REG_ISTAT, tmp); ++ } ++ ++ /* back to the noise mode */ ++ ret = nisttrng_set_nonce_mode(nist_trng, 0); ++ if (ret) ++ goto ERR; ++ ++ ret = nisttrng_zeroize(nist_trng); ++ if (ret) ++ goto ERR; ++ERR: ++ return ret; ++} ++ ++static int nisttrng_driver_probe(struct platform_device *pdev) ++{ ++ struct synopsys_nisttrng_driver *data; ++ struct hwrng *hwrng_driver_info = 0; ++ struct resource *cfg, *irq; ++ u32 *base_addr; ++ int ret; ++ ++ // version ++ SYNHW_PRINT("DWC_TRNG_DriverSDK_%s\n", TRNG_VERSION); ++ ++ cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ ++ if (!cfg || !irq) { ++ SYNHW_PRINT("no memory or IRQ resource\n"); ++ return -ENOMEM; ++ } ++ ++ DEBUG("=================================================================\n"); ++ DEBUG("nisttrng_probe: Device at %08lx(%08lx) of size %lu bytes\n", ++ (unsigned long)cfg->start, (unsigned long)cfg->end, ++ (unsigned long)resource_size(cfg)); ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(struct synopsys_nisttrng_driver), ++ GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, data); ++ ++ base_addr = pdu_linux_map_regs(&pdev->dev, cfg); ++ if (IS_ERR(base_addr)) { ++ dev_err(&pdev->dev, "unable to remap io mem\n"); ++ return PTR_ERR(base_addr); ++ } ++ ++ ret = nisttrng_init(&data->nisttrng, (u32 *)base_addr); ++ if (ret) { ++ SYNHW_PRINT("NIST_TRNG init failed (%d)\n", ret); ++ devm_kfree(&pdev->dev, data); ++ return ret; ++ } ++ ++ /* if max_reads is not 0, change the max_req_per_seed according to max_reads */ ++ if (max_reads) { ++ ret = nisttrng_set_reminder_max_req_per_seed(&data->nisttrng, max_reads); ++ if (ret) { ++ SYNHW_PRINT("NIST_TRNG maximum request-per-seed setup failed (%d)\n", ++ ret); ++ devm_kfree(&pdev->dev, data); ++ return ret; ++ } ++ } ++ ++ // issue quick self test ++ ret = nisttrng_self_test(&data->nisttrng); ++ if (ret) { ++ devm_kfree(&pdev->dev, data); ++ return -ENOMEM; ++ } ++ ++ // ready the device for use ++ ret = nisttrng_instantiate(&data->nisttrng, ++ data->nisttrng.config.features.drbg_arch ? 256 : 128, 1, NULL); ++ if (ret) { ++ SYNHW_PRINT("NIST_TRNG instantiate failed (%d)\n", ret); ++ devm_kfree(&pdev->dev, data); ++ return -ENOMEM; ++ } ++ ++ // at this point the device should be ready for a call to gen_random ++ hwrng_driver_info = ++ devm_kzalloc(&pdev->dev, sizeof(struct hwrng), GFP_KERNEL); ++ if (!hwrng_driver_info) { ++ devm_kfree(&pdev->dev, data); ++ return -ENOMEM; ++ } ++ ++ hwrng_driver_info->name = devm_kzalloc(&pdev->dev, ++ sizeof(SYNOPSYS_HWRNG_DRIVER_NAME) + 1, GFP_KERNEL); ++ if (!hwrng_driver_info->name) { ++ devm_kfree(&pdev->dev, data); ++ devm_kfree(&pdev->dev, hwrng_driver_info); ++ return -ENOMEM; ++ } ++ ++ memset((void *)hwrng_driver_info->name, 0, ++ sizeof(SYNOPSYS_HWRNG_DRIVER_NAME) + 1); ++ strscpy((char *)hwrng_driver_info->name, SYNOPSYS_HWRNG_DRIVER_NAME, ++ sizeof(SYNOPSYS_HWRNG_DRIVER_NAME)); ++ ++ hwrng_driver_info->read = &nisttrng_hwrng_driver_read; ++ hwrng_driver_info->data_present = 0; ++ hwrng_driver_info->priv = (unsigned long)pdev; ++ hwrng_driver_info->quality = 1024; ++ ++ data->hwrng_drv = hwrng_driver_info; ++ ret = hwrng_register(hwrng_driver_info); ++ ++ if (ret) { ++ SYNHW_PRINT("unable to load HWRNG driver (error %d)\n", ret); ++ devm_kfree(&pdev->dev, (void *)hwrng_driver_info->name); ++ devm_kfree(&pdev->dev, hwrng_driver_info); ++ devm_kfree(&pdev->dev, data); ++ return ret; ++ } ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &nisttrng_attr_group); ++ if (ret < 0) { ++ SYNHW_PRINT("unable to initialize sysfs group (error %d)\n", ++ ret); ++ hwrng_unregister(hwrng_driver_info); ++ devm_kfree(&pdev->dev, (void *)hwrng_driver_info->name); ++ devm_kfree(&pdev->dev, hwrng_driver_info); ++ devm_kfree(&pdev->dev, data); ++ return ret; ++ } ++ SYNHW_PRINT("SYN NIST_TRNG registering HW_RANDOM\n"); ++ return 0; ++} ++ ++static void nisttrng_driver_remove(struct platform_device *pdev) ++{ ++ struct synopsys_nisttrng_driver *data = platform_get_drvdata(pdev); ++ struct hwrng *hwrng_driver_info = (struct hwrng *)data->hwrng_drv; ++ ++ SYNHW_PRINT("SYN NIST_TRNG unregistering from HW_RANDOM\n"); ++ hwrng_unregister(hwrng_driver_info); ++ sysfs_remove_group(&pdev->dev.kobj, &nisttrng_attr_group); ++ devm_kfree(&pdev->dev, (void *)hwrng_driver_info->name); ++ devm_kfree(&pdev->dev, hwrng_driver_info); ++ devm_kfree(&pdev->dev, data); ++} ++ ++static struct platform_driver s_nisttrng_platform_driver_info = { ++ .probe = nisttrng_driver_probe, ++ .remove = nisttrng_driver_remove, ++ .driver = { ++ .name = "nist_trng", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init nisttrng_platform_driver_start(void) ++{ ++ return platform_driver_register(&s_nisttrng_platform_driver_info); ++} ++ ++static void __exit nisttrng_platform_driver_end(void) ++{ ++ platform_driver_unregister(&s_nisttrng_platform_driver_info); ++} ++ ++module_init(nisttrng_platform_driver_start); ++module_exit(nisttrng_platform_driver_end); ++ ++module_param(max_reads, ulong, 0); ++MODULE_PARM_DESC(max_reads, "Max # of reads between reseeds (default is 128)"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Synopsys, Inc."); +diff --git a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c +--- a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng.c 2026-09-09 15:51:42.910265392 +0000 +@@ -0,0 +1,956 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "nisttrng_hw.h" ++#include "nisttrng.h" ++ ++/* Initialize the NIST_TRNG state structure */ ++int nisttrng_init(struct nist_trng_state *state, u32 *base) ++{ ++ int err; ++ u32 tmp; ++ ++ DEBUG(">> %s: initialize the NIST_TRNG\n", __func__); ++ ++ memset(state, 0, sizeof(*state)); ++ ++ state->base = base; ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* hardware features*/ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_FEATURES); ++ ++ state->config.features.drbg_arch = NIST_TRNG_REG_FEATURES_AES_256(tmp); ++ state->config.features.extra_ps_present = ++ NIST_TRNG_REG_FEATURES_EXTRA_PS_PRESENT(tmp); ++ state->config.features.secure_rst_state = ++ NIST_TRNG_REG_FEATURES_SECURE_RST_STATE(tmp); ++ state->config.features.diag_level_basic_trng = ++ NIST_TRNG_REG_FEATURES_DIAG_LEVEL_BASIC_TRNG(tmp); ++ state->config.features.diag_level_stat_hlt = ++ NIST_TRNG_REG_FEATURES_DIAG_LEVEL_ST_HLT(tmp); ++ state->config.features.diag_level_ns = ++ NIST_TRNG_REG_FEATURES_DIAG_LEVEL_NS(tmp); ++ ++ /* corekit */ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_COREKIT_REL); ++ state->config.corekit_rel.ext_enum = NIST_TRNG_REG_EXT_ENUM(tmp); ++ state->config.corekit_rel.ext_ver = NIST_TRNG_REG_EXT_VER(tmp); ++ state->config.corekit_rel.rel_num = NIST_TRNG_REG_REL_NUM(tmp); ++ ++ /* clear registers */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_ALARM, 0xFFFFFFFF); ++ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, 0xFFFFFFFF); ++ ++ /* setup the NIST_TRNG in secure mode, self seeding mode, with prediction resistance, maximum possible security strength */ ++ /* SMODE */ ++ tmp = 0; ++ tmp = NIST_TRNG_REG_SMODE_SET_SECURE_EN(tmp, 1); ++ tmp = NIST_TRNG_REG_SMODE_SET_NONCE(tmp, 0); ++ tmp = NIST_TRNG_REG_SMODE_SET_MAX_REJECTS(tmp, ++ NIST_TRNG_DFLT_MAX_REJECTS); ++ pdu_io_write32(state->base + NIST_TRNG_REG_SMODE, tmp); ++ state->status.secure_mode = 1; ++ state->status.nonce_mode = 0; ++ /* MODE */ ++ tmp = 0; ++ if (state->config.features.drbg_arch == AES256) { ++ tmp = NIST_TRNG_REG_MODE_SET_SEC_ALG(tmp, 1); ++ state->status.sec_strength = SEC_STRNT_AES256; ++ ++ } else if (state->config.features.drbg_arch == AES128) { ++ tmp = NIST_TRNG_REG_MODE_SET_SEC_ALG(tmp, 0); ++ state->status.sec_strength = SEC_STRNT_AES128; ++ ++ } else { ++ SYNHW_PRINT("Invalid DRBG architecture"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ tmp = NIST_TRNG_REG_MODE_SET_PRED_RESIST(tmp, 1); ++ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, 0); ++ state->status.pred_resist = 1; ++ /* rest of the status */ ++ state->status.alarm_code = 0; ++ state->status.pad_ps_addin = 0; ++ ++ /* reminders - set the counters to the standard's maximum values. An API is be provided to change those on demand.*/ ++ nisttrng_set_reminder_max_bits_per_req(state, ++ NIST_DFLT_MAX_BITS_PER_REQ); ++ nisttrng_set_reminder_max_req_per_seed(state, ++ NIST_DFLT_MAX_REQ_PER_SEED); ++ ++ /* display features */ ++ SYNHW_PRINT("NIST_TRNG: Hardware rel_num=0x%x, ext_ver=0x%x, ext_enum=0x%x\n", ++ state->config.corekit_rel.rel_num, ++ state->config.corekit_rel.ext_ver, ++ state->config.corekit_rel.ext_enum); ++ switch (state->config.features.drbg_arch) { ++ case AES128: ++ DEBUG("NIST_TRNG: DRBG Architecture=128-bit AES, Extra Personalization Existence=%u\n", ++ state->config.features.extra_ps_present); ++ break; ++ case AES256: ++ DEBUG("NIST_TRNG: DRBG Architecture=256-bit AES, Extra Personalization Existence=%u\n", ++ state->config.features.extra_ps_present); ++ break; ++ default: ++ SYNHW_PRINT("Invalid DRBG architecture"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ DEBUG("initialization is done, going for a zeroize\n"); ++ ++ // BUILD_CFG0 ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_BUILD_CFG0); ++ state->config.build_cfg0.core_type = NIST_TRNG_REG_CFG0_CORE_TYPE(tmp); ++ state->config.build_cfg0.bg8 = NIST_TRNG_REG_CFG0_BG8(tmp); ++ state->config.build_cfg0.cdc_synch_depth = ++ NIST_TRNG_REG_CFG0_CDC_SYNCH_DEPTH(tmp); ++ state->config.build_cfg0.background_noise = ++ NIST_TRNG_REG_CFG0_BACGROUND_NOISE(tmp); ++ state->config.build_cfg0.edu_present = ++ NIST_TRNG_REG_CFG0_EDU_PRESENT(tmp); ++ state->config.build_cfg0.aes_datapath = ++ NIST_TRNG_REG_CFG0_AES_DATAPATH(tmp); ++ state->config.build_cfg0.aes_max_key_size = ++ NIST_TRNG_REG_CFG0_AES_MAX_KEY_SIZE(tmp); ++ state->config.build_cfg0.personilzation_str = ++ NIST_TRNG_REG_CFG0_PERSONILIZATION_STR(tmp); ++ DEBUG("NIST_TRNG: BUILD_CFG0 core_type=%u, bg8=%u, cdc_synch_depth=%u, background_noise=%u\n", ++ state->config.build_cfg0.core_type, state->config.build_cfg0.bg8, ++ state->config.build_cfg0.cdc_synch_depth, ++ state->config.build_cfg0.background_noise); ++ DEBUG("edu_present=%u, aes_datapath=%u, aes_max_key_size=%u, personilzation_str=%u\n", ++ state->config.build_cfg0.edu_present, ++ state->config.build_cfg0.aes_datapath, ++ state->config.build_cfg0.aes_max_key_size, ++ state->config.build_cfg0.personilzation_str); ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_BUILD_CFG1); ++ DEBUG("NIST_TRNG: NIST_TRNG_REG_BUILD_CFG1=0x%x\n", tmp); ++ state->config.build_cfg1.num_raw_noise_blks = ++ NIST_TRNG_REG_CFG1_NUM_RAW_NOISE_BLKS(tmp); ++ state->config.build_cfg1.sticky_startup = ++ NIST_TRNG_REG_CFG1_STICKY_STARTUP(tmp); ++ state->config.build_cfg1.auto_correlation_test = ++ NIST_TRNG_REG_CFG1_AUTO_CORRELATION_TEST(tmp); ++ state->config.build_cfg1.mono_bit_test = ++ NIST_TRNG_REG_CFG1_MONO_BIT_TEST(tmp); ++ state->config.build_cfg1.run_test = NIST_TRNG_REG_CFG1_RUN_TEST(tmp); ++ state->config.build_cfg1.poker_test = ++ NIST_TRNG_REG_CFG1_POKER_TEST(tmp); ++ state->config.build_cfg1.raw_ht_adap_test = ++ NIST_TRNG_REG_CFG1_RAW_HT_ADAP_TEST(tmp); ++ state->config.build_cfg1.raw_ht_rep_test = ++ NIST_TRNG_REG_CFG1_RAW_HT_REP_TEST(tmp); ++ state->config.build_cfg1.ent_src_rep_smpl_size = ++ NIST_TRNG_REG_CFG1_ENT_SRC_REP_SMPL_SIZE(tmp); ++ state->config.build_cfg1.ent_src_rep_test = ++ NIST_TRNG_REG_CFG1_ENT_SRC_REP_TEST(tmp); ++ state->config.build_cfg1.ent_src_rep_min_entropy = ++ NIST_TRNG_REG_CFG1_ENT_SRC_REP_MIN_ENTROPY(tmp); ++ DEBUG("NIST_TRNG: BUILD_CFG1 num_raw_noise_blks=%u, sticky_startup=%u, auto_correlation_test=%u\n", ++ state->config.build_cfg1.num_raw_noise_blks, ++ state->config.build_cfg1.sticky_startup, ++ state->config.build_cfg1.auto_correlation_test); ++ DEBUG("mono_bit_test=%u, run_test=%u, poker_test=%u, raw_ht_adap_test=%u\n", ++ state->config.build_cfg1.mono_bit_test, ++ state->config.build_cfg1.run_test, ++ state->config.build_cfg1.poker_test, ++ state->config.build_cfg1.raw_ht_adap_test); ++ DEBUG("raw_ht_rep_test=%u, ent_src_rep_smpl_size=%u, ent_src_rep_test=%u, ent_src_rep_min_entropy=%u\n", ++ state->config.build_cfg1.raw_ht_rep_test, ++ state->config.build_cfg1.ent_src_rep_smpl_size, ++ state->config.build_cfg1.ent_src_rep_test, ++ state->config.build_cfg1.ent_src_rep_min_entropy); ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_BUILD_CFG0); ++ state->config.edu_build_cfg0.rbc2_rate_width = ++ NIST_TRNG_REG_EDU_CFG0_RBC2_RATE_WIDTH(tmp); ++ state->config.edu_build_cfg0.rbc1_rate_width = ++ NIST_TRNG_REG_EDU_CFG0_RBC1_RATE_WIDTH(tmp); ++ state->config.edu_build_cfg0.rbc0_rate_width = ++ NIST_TRNG_REG_EDU_CFG0_RBC0_RATE_WIDTH(tmp); ++ state->config.edu_build_cfg0.public_vtrng_channels = ++ NIST_TRNG_REG_EDU_CFG0_PUBLIC_VTRNG_CHANNELS(tmp); ++ state->config.edu_build_cfg0.esm_channel = ++ NIST_TRNG_REG_EDU_CFG0_ESM_CHANNEL(tmp); ++ state->config.edu_build_cfg0.rbc_channels = ++ NIST_TRNG_REG_EDU_CFG0_RBC_CHANNELS(tmp); ++ state->config.edu_build_cfg0.fifo_depth = ++ NIST_TRNG_REG_EDU_CFG0_FIFO_DEPTH(tmp); ++ DEBUG("NIST_TRNG: EDU_BUILD_CFG0 rbc2_rate_width=%u, rbc1_rate_width=%u, rbc0_rate_width=%u\n", ++ state->config.edu_build_cfg0.rbc2_rate_width, ++ state->config.edu_build_cfg0.rbc1_rate_width, ++ state->config.edu_build_cfg0.rbc0_rate_width); ++ DEBUG("public_vtrng_channels=%u, esm_channel=%u, rbc_channels=%u, fifo_depth=%u\n", ++ state->config.edu_build_cfg0.public_vtrng_channels, ++ state->config.edu_build_cfg0.esm_channel, ++ state->config.edu_build_cfg0.rbc_channels, ++ state->config.edu_build_cfg0.fifo_depth); ++ ++ state->status.edu_vstat.seed_enum = ++ NIST_TRNG_REG_EDU_VSTAT_SEED_ENUM(tmp); ++ state->status.edu_vstat.rnc_enabled = ++ NIST_TRNG_REG_EDU_VSTAT_RNC_ENABLED(tmp); ++ ++ err = nisttrng_zeroize(state); ++ if (err) ++ goto ERR; ++ ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_INITIALIZE; ++ERR: ++ DEBUG("--- %s Return, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_init */ ++EXPORT_SYMBOL(nisttrng_init); ++ ++/* Instantiate the DRBG state */ ++int nisttrng_instantiate(struct nist_trng_state *state, int req_sec_strength, ++ int pred_resist, void *personal_str) ++{ ++ int err; ++ u32 tmp; ++ u32 zero_ps[12] = { 0 }; ++ int i = 0; ++ ++ DEBUG(">> %s: security strength = %u, pred_resist = %u, personilization string existence = %u\n", ++ __func__, req_sec_strength, pred_resist, (personal_str) ? 1 : 0); ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* If DRBG is already instantiated or if current state does not allow an instantiate, return error */ ++ if (DRBG_INSTANTIATED(state->status.current_state)) { ++ DEBUG("Initial check: DRBG state is already instantiated\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ if (state->status.current_state != NIST_TRNG_STATE_INITIALIZE && ++ state->status.current_state != NIST_TRNG_STATE_UNINSTANTIATE) { ++ DEBUG("Cannot instantiate in the current state (%u)\n", ++ state->status.current_state); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* if hardware is not configured to accept extra personalization string, but personal_str is not NULL, return error */ ++ if (!state->config.features.extra_ps_present && personal_str) { ++ DEBUG("HW config does not allow extra PS\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* Validate and set the security strength */ ++ err = nisttrng_set_sec_strength(state, req_sec_strength); ++ if (err) ++ goto ERR; ++ ++ /* get entropy - noise seeding. If the mode is nonce, get_entropy must be called by the user prior to the instantiate function */ ++ DEBUG("Seeding mode is: %s\n", ++ state->status.nonce_mode ? "Nonce" : "Noise"); ++ if (!state->status.nonce_mode) { /* noise seeding */ ++ err = nisttrng_get_entropy_input(state, NULL, 0); ++ if (err) ++ goto ERR; ++ } ++ ++ /* load the personilization string if hardware is configured to accept it */ ++ if (state->config.features.extra_ps_present) { ++ /* if HW is configured to accept personilizatoin string, it will use whatever is in the NPA_DATAx. So, if the string is NULL, just load 0. */ ++ if (!personal_str) ++ personal_str = &zero_ps[0]; ++ ++ err = nisttrng_load_ps_addin(state, personal_str); ++ if (err) ++ goto ERR; ++ } ++ ++ /* initiate the Create_State command and wait on done */ ++ DEBUG("Create the DRBG state\n"); ++ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_CREATE_STATE); ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; ++ ++ /* check STAT register to make sure DRBG is instantiated */ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); ++ if (!NIST_TRNG_REG_STAT_GET_DRBG_STATE(tmp)) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* reset reminder and alarms counters */ ++ nisttrng_reset_counters(state); ++ ++ //if EDU is available enable RNC and disable prediction resistance , disable all RBC,s ++ //state->config.build_cfg0.edu_present = 0; ++ if (state->config.build_cfg0.edu_present) { ++ //disable prediction resistance ++ err = nisttrng_set_pred_resist(state, 0); ++ if (err) ++ goto ERR; ++ ++ //enable RNC ++ nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE); ++ // disable all RBC,s ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); ++ for (i = 0; i < state->config.edu_build_cfg0.rbc_channels; ++ i++) { ++ err = nisttrng_rbc(state, 0, i, 0, ++ CHX_URUN_BLANK_AFTER_RESET); ++ if (err) ++ goto ERR; ++ } ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); ++ ++ } else { ++ /* set the prediction resistance */ ++ err = nisttrng_set_pred_resist(state, pred_resist); ++ if (err) ++ goto ERR; ++ } ++ ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_INSTANTIATE; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_instantiate */ ++EXPORT_SYMBOL(nisttrng_instantiate); ++ ++/* Uninstantiate the DRBG state and zeroize */ ++int nisttrng_uninstantiate(struct nist_trng_state *state) ++{ ++ int err; ++ int err_tmp; ++ u32 tmp; ++ ++ DEBUG(">> %s: uninstantiate the DRBG and zeroize\n", __func__); ++ //printf(" nisttrng_uninstantiate: uninstantiate the DRBG and zeroize\n"); ++ err = CRYPTO_OK; ++ err_tmp = CRYPTO_OK; ++ ++ //disable RNC ++ if (state->config.build_cfg0.edu_present) { ++ if (state->status.edu_vstat.rnc_enabled) { ++ DEBUG("%s: disable RNC\n", __func__); ++ nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE); ++ //always clear the busy bit after disabling RNC ++ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, tmp); ++ } ++ } ++ ++ /* if DRBG is instantiated, return CRYPTO_NOT_INSTANTIATED, but still do the zeroize */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) ++ err_tmp = CRYPTO_NOT_INSTANTIATED; ++ ++ /* zeroize */ ++ err = nisttrng_zeroize(state); ++ if (err) ++ goto ERR; ++ ++ if (err == CRYPTO_OK && err_tmp == CRYPTO_NOT_INSTANTIATED) ++ err = CRYPTO_NOT_INSTANTIATED; ++ ++ state->status.current_state = NIST_TRNG_STATE_UNINSTANTIATE; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_uninstantiate */ ++EXPORT_SYMBOL(nisttrng_uninstantiate); ++ ++/* enable/disable specific rbc ++ * rbc_num = rbc channel num ++ * urun_blnk = underrun blanking duration for rbc channel ++ * rate = sets rate of serial entropy output for rbc channel ++ */ ++int nisttrng_rbc(struct nist_trng_state *state, int enable, int rbc_num, int rate, ++ int urun_blnk) ++{ ++ int err = 0; ++ u32 tmp_rbc = 0; ++ ++ tmp_rbc = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); ++ ++ if (enable) { ++ if (rate > 15) { ++ DEBUG("Incorrect rate = %d\n", rate); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ if (urun_blnk > 3) { ++ DEBUG("Incorrect urun_blnk = %d\n", urun_blnk); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ } else { //disable ++ rate = NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE_AFTER_RESET; ++ urun_blnk = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK_AFTER_RESET; ++ } ++ ++ switch (rbc_num) { ++ case 0: ++ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(rate, tmp_rbc, _NIST_TRNG_EDU_RBC_CTRL_CH0_RATE); ++ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(urun_blnk, tmp_rbc, ++ _NIST_TRNG_EDU_RBC_CTRL_CH0_URUN_BLANK); ++ ++ break; ++ case 1: ++ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(rate, tmp_rbc, _NIST_TRNG_EDU_RBC_CTRL_CH1_RATE); ++ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(urun_blnk, tmp_rbc, ++ _NIST_TRNG_EDU_RBC_CTRL_CH1_URUN_BLANK); ++ ++ break; ++ case 2: ++ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_RATE(rate, tmp_rbc, _NIST_TRNG_EDU_RBC_CTRL_CH2_RATE); ++ tmp_rbc = NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK(urun_blnk, tmp_rbc, ++ _NIST_TRNG_EDU_RBC_CTRL_CH2_URUN_BLANK); ++ break; ++ default: ++ DEBUG("Incorrect rbc_num = %d\n", rbc_num); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ pdu_io_write32(state->base + NIST_TRNG_EDU_RBC_CTRL, tmp_rbc); ++ ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++ ++/* Reseed */ ++int nisttrng_reseed(struct nist_trng_state *state, int pred_resist, void *addin_str) ++{ ++ int rnc_flag = 0; ++ int err; ++ ++ DEBUG(">> %s: pred_resist = %u, additional strign existence = %u\n", ++ __func__, pred_resist, (addin_str) ? 1 : 0); ++ ++ if (state->config.build_cfg0.edu_present) { ++ if (state->status.edu_vstat.rnc_enabled) { ++ // disable_rnc ++ err = nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_DISABLE_TO_HOLD); ++ if (err) ++ goto ERR; ++ ++ rnc_flag = 1; ++ } ++ } ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* if the DRBG is not instantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ DEBUG("DRBG is not instantiated\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* if pred_resist is set but, pred_resist that the DRBG is instantiated with is not 1, return error */ ++ err = nisttrng_set_pred_resist(state, pred_resist); ++ if (err) ++ goto ERR; ++ ++ /* get entropy - noise seeding. If the mode is nonce, get_entropy must be called by the user prior to the instantiate function */ ++ if (!state->status.nonce_mode) { /* noise seeding */ ++ err = nisttrng_get_entropy_input(state, NULL, 0); ++ if (err) ++ goto ERR; ++ } ++ ++ /* if addin_str is not NULL, it means that the additionl input is available and has to be loaded */ ++ if (addin_str) { ++ /* set the ADDIN_PRESENT field of the MODE register to 1 */ ++ err = nisttrng_set_addin_present(state, 1); ++ if (err) ++ goto ERR; ++ ++ /* load the additional input */ ++ err = nisttrng_load_ps_addin(state, addin_str); ++ if (err) ++ goto ERR; ++ ++ } else { ++ /* set the ADDIN_PRESENT field of the MODE register to 0 */ ++ err = nisttrng_set_addin_present(state, 0); ++ if (err) ++ goto ERR; ++ } ++ ++ /* initiate the reseed and wait on done */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_RENEW_STATE); ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; ++ ++ /* reset reminder and alarms counters */ ++ nisttrng_reset_counters(state); ++ ++ if (rnc_flag) { ++ // rnc_enable ++ err = nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE); ++ if (err) ++ goto ERR; ++ } ++ ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_RESEED; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_reseed */ ++EXPORT_SYMBOL(nisttrng_reseed); ++ ++static int nisttrng_vtrng_wait_on_busy(struct nist_trng_state *state, int priv, int vtrng) ++{ ++ u32 tmp, t; ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ if (priv) { //private vtrng ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VSTAT); ++ } while (NIST_TRNG_REG_EDU_VSTAT_BUSY(tmp) && --t); ++ ++ } else { //public vtrng ++ do { ++ tmp = pdu_io_read32(state->base + ++ NIST_TRNG_EDU_VTRNG_VSTAT0 + ++ 8 * vtrng); ++ } while (NIST_TRNG_REG_EDU_VSTAT_BUSY(tmp) && --t); ++ } ++ ++ if (t) ++ return CRYPTO_OK; ++ ++ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", ++ (unsigned long)tmp); ++ ++ return CRYPTO_TIMEOUT; ++} /* nisttrng_vtrng_wait_on_busy */ ++ ++int nisttrng_generate_public_vtrng(struct nist_trng_state *state, void *random_bits, ++ unsigned long req_num_bytes, int vtrng) ++{ ++ int err = 0; ++ u32 tmp; ++ unsigned int remained_bytes; ++ unsigned long req_num_blks; ++ int i, j; ++ ++ DEBUG(">> %s : requested number of bytes = %lu, vtrng num = %u\n", ++ __func__, req_num_bytes, vtrng); ++ ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ DEBUG("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ if (vtrng > state->config.edu_build_cfg0.public_vtrng_channels) { ++ DEBUG("vtrng channel invalid (%u)\n", vtrng); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ if (state->status.edu_vstat.rnc_enabled == 0) { ++ DEBUG("rnc_disabled\n"); ++ } ++ ++ if (state->status.edu_vstat.seed_enum == 0) { ++ DEBUG("not seed_enum\n"); ++ } ++ ++ /* loop on generate to get the requested number of bits. Each generate gives NIST_TRNG_RAND_BLK_SIZE_BITS bits. */ ++ req_num_blks = ((req_num_bytes * 8) % NIST_TRNG_RAND_BLK_SIZE_BITS) ? ++ (((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS) + 1) : ++ ((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS); ++ ++ for (i = 0; i < req_num_blks; i++) { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VTRNG_VCTRL0 + ++ (vtrng * 8)); ++ tmp = NIST_TRNG_EDU_VTRNG_VCTRL_CMD_SET(tmp, NIST_TRNG_EDU_VTRNG_VCTRL_CMD_GET_RANDOM); ++ pdu_io_write32(state->base + NIST_TRNG_EDU_VTRNG_VCTRL0 + (vtrng * 8), ++ tmp); ++ ++ // check busy ++ err = nisttrng_vtrng_wait_on_busy(state, 0, vtrng); ++ if (err) ++ goto ERR; ++ ++ // check for error ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VTRNG_VISTAT0 + ++ (vtrng * 8)); ++ if (NIST_TRNG_REG_EDU_VSTAT_ANY_RW1(tmp)) { ++ DEBUG("EDU_VSTAT_ANY_RW1 set 0x%x\n", tmp); ++ } ++ ++ // check that all valid ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VTRNG_VSTAT0 + ++ 8 * vtrng); ++ if ((NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD0(tmp) == 0) || ++ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD1(tmp) == 0) || ++ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD2(tmp) == 0) || ++ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD3(tmp) == 0)) { ++ DEBUG("EDU_VSTAT_SLICE_VLD fail 0x%x\n", tmp); ++ } ++ ++ /* read the generated random number block and store */ ++ for (j = 0; j < (NIST_TRNG_RAND_BLK_SIZE_BITS / 32); j++) { ++ tmp = pdu_io_read32(state->base + ++ NIST_TRNG_EDU_VTRNG_VRAND0_0 + ++ (vtrng * 8) + j); ++ /* copy to random_bits byte-by-byte, until req_num_bytes are copied */ ++ remained_bytes = req_num_bytes - ++ (i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4); ++ if (remained_bytes > 4) { ++ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, 4); ++ ++ /* decrement the bits counter and return error if generated more than the maximum*/ ++ state->counters.bits_per_req_left = ++ state->counters.bits_per_req_left - ++ 4 * 8; ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ } else { ++ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, remained_bytes); ++ ++ /* decrement the bits counter and return error if generated more than the maximum*/ ++ state->counters.bits_per_req_left = ++ state->counters.bits_per_req_left - ++ remained_bytes * 8; ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ break; ++ } ++ } ++ } ++ ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_GENERATE; ++ERR: ++ if (err) ++ random_bits = NULL; ++ ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++ ++static int nisttrng_generate_private_vtrng(struct nist_trng_state *state, void *random_bits, ++ unsigned long req_num_bytes) ++{ ++ int err; ++ u32 tmp; ++ unsigned int remained_bytes; ++ unsigned long req_num_blks; ++ int i, j; ++ ++ DEBUG(">> %s : requested number of bytes = %lu ", ++ __func__, req_num_bytes); ++ ++ /* requested number of bits has to be less that the programmed maximum */ ++ if ((req_num_bytes * 8) > state->counters.max_bits_per_req) { ++ SYNHW_PRINT("requested number of bits (%lu) is larger than the set maximum (%lu)\n", ++ (req_num_bytes * 8), state->counters.max_bits_per_req); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ SYNHW_PRINT("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ if (state->status.edu_vstat.rnc_enabled == 0) { ++ DEBUG("rnc_disabled\n"); ++ } ++ ++ if (state->status.edu_vstat.seed_enum == 0) { ++ DEBUG("not seed_enum\n"); ++ } ++ ++ /* loop on generate to get the requested number of bits. Each generate gives NIST_TRNG_RAND_BLK_SIZE_BITS bits. */ ++ req_num_blks = ((req_num_bytes * 8) % NIST_TRNG_RAND_BLK_SIZE_BITS) ? ++ (((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS) + 1) : ++ ((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS); ++ ++ for (i = 0; i < req_num_blks; i++) { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VCTRL); ++ tmp = NIST_TRNG_EDU_VTRNG_VCTRL_CMD_SET(tmp, NIST_TRNG_EDU_VTRNG_VCTRL_CMD_GET_RANDOM); ++ pdu_io_write32(state->base + NIST_TRNG_EDU_VCTRL, tmp); ++ ++ // check busy ++ err = nisttrng_vtrng_wait_on_busy(state, 1, 0); ++ if (err) ++ goto ERR; ++ ++ // check for error ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VISTAT); ++ if (NIST_TRNG_REG_EDU_VSTAT_ANY_RW1(tmp)) { ++ DEBUG("EDU_VSTAT_ANY_RW1 set 0x%x\n", tmp); ++ } ++ ++ //check that all valid ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VSTAT); ++ if ((NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD0(tmp) == 0) || ++ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD1(tmp) == 0) || ++ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD2(tmp) == 0) || ++ (NIST_TRNG_REG_EDU_VSTAT_SLICE_VLD3(tmp) == 0)) { ++ DEBUG("EDU_VSTAT_SLICE_VLD fail 0x%x\n", tmp); ++ } ++ ++ /* read the generated random number block and store */ ++ for (j = 0; j < (NIST_TRNG_RAND_BLK_SIZE_BITS / 32); j++) { ++ tmp = pdu_io_read32(state->base + ++ NIST_TRNG_EDU_VRAND_0 + j); ++ /* copy to random_bits byte-by-byte, until req_num_bytes are copied */ ++ remained_bytes = req_num_bytes - ++ (i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4); ++ if (remained_bytes > 4) { ++ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, 4); ++ ++ /* decrement the bits counter and return error if generated more than the maximum*/ ++ state->counters.bits_per_req_left = ++ state->counters.bits_per_req_left - ++ 4 * 8; ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ } else { ++ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, remained_bytes); ++ ++ /* decrement the bits counter and return error if generated more than the maximum*/ ++ state->counters.bits_per_req_left = ++ state->counters.bits_per_req_left - ++ remained_bytes * 8; ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ break; ++ } ++ } ++ } ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++ ++/* Generate */ ++int nisttrng_generate(struct nist_trng_state *state, void *random_bits, ++ unsigned long req_num_bytes, int req_sec_strength, ++ int pred_resist, void *addin_str) ++{ ++ int err; ++ int reseed_required; ++ ++ DEBUG(">> %s: requested number of bytes = %lu, security strength = %u, pred_resist = %u, additional string existence = %u\n", ++ __func__, req_num_bytes, req_sec_strength, pred_resist, ++ (addin_str) ? 1 : 0); ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* if the DRBG is not instantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ SYNHW_PRINT("DRBG is not instantiated\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* requested number of bits has to be less that the programmed maximum */ ++ if ((req_num_bytes * 8) > state->counters.max_bits_per_req) { ++ SYNHW_PRINT("requested number of bits (%lu) is larger than the set maximum (%lu)\n", ++ (req_num_bytes * 8), state->counters.max_bits_per_req); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* security strength has to be lower than what the DRBG is instantiated with. set_sec_strength function checks this. */ ++ err = nisttrng_set_sec_strength(state, req_sec_strength); ++ if (err) ++ goto ERR; ++ ++ /* set the prediction resistance - if pred_resist is set but, pred_resist that the DRBG is instantiated with is not 1, return error */ ++ err = nisttrng_set_pred_resist(state, pred_resist); ++ if (err) ++ goto ERR; ++ ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ DEBUG("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* set the reseed required flag to 0. The loop is to check at the end whether a reseed is required at the end and jump back to reseed and generate if needed. This is the NIST mandated procedure */ ++ reseed_required = 0; ++ ++ if (!addin_str) { ++ /* set the ADDIN_PRESENT field of the MODE register to 1 */ ++ err = nisttrng_set_addin_present(state, 0); ++ if (err) ++ goto ERR; ++ } ++ ++ do { ++ void *generate_addin_str = addin_str; ++ ++ if (pred_resist | reseed_required) { ++ err = nisttrng_reseed(state, pred_resist, addin_str); ++ if (err) ++ goto ERR; ++ ++ /* SP800-90a says that if reseed is executed, any additional input string is only used in the reseed phase and replaced by NULL in the generate phase */ ++ generate_addin_str = NULL; ++ err = nisttrng_set_addin_present(state, 0); ++ if (err) ++ goto ERR; ++ ++ /* ADDIN_PRESENT field in MODE has to be set back to 0 to avoid illegal cmd sequence */ ++ reseed_required = 0; ++ } ++ ++ /* generate process */ ++ if (nisttrng_check_seed_lifetime(state) == CRYPTO_RESEED_REQUIRED) { ++ reseed_required = 1; ++ ++ } else { ++ reseed_required = 0; ++ ++ /* Refresh_Addin command if additional input is not NULL*/ ++ if (generate_addin_str) { ++ err = nisttrng_refresh_addin(state, generate_addin_str); ++ if (err) ++ goto ERR; ++ } ++ ++ /* Generate all random bits */ ++ /* if EDU present then get random number from private vtrng */ ++ ++ //state->config.build_cfg0.edu_present = 0; ++ if (state->config.build_cfg0.edu_present) { ++ err = nisttrng_generate_private_vtrng(state, random_bits, ++ req_num_bytes); ++ if (err) ++ goto ERR; ++ ++ } else { ++ err = nisttrng_gen_random(state, random_bits, ++ req_num_bytes); ++ if (err) ++ goto ERR; ++ ++ /* Advance the state - if it returns CRYPTO_RESEED_REQUIRED, have to jump back and do a reseed and generate */ ++ err = nisttrng_advance_state(state); ++ if (err) ++ goto ERR; ++ } ++ } ++ } while (reseed_required); ++ ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_GENERATE; ++ERR: ++ if (err) ++ random_bits = NULL; ++ ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_generate */ ++EXPORT_SYMBOL(nisttrng_generate); +diff --git a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c +--- a/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/char/hw_random/dwc/src/trng/trng/nist_trng_private.c 2026-09-09 15:51:42.910265392 +0000 +@@ -0,0 +1,1022 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This Synopsys software and associated documentation (hereinafter the ++ * "Software") is an unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. The ++ * Software IS NOT an item of Licensed Software or a Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Products ++ * with Synopsys or any supplement thereto. Synopsys is a registered trademark ++ * of Synopsys, Inc. Other names included in the SOFTWARE may be the ++ * trademarks of their respective owners. ++ * ++ * The contents of this file are dual-licensed; you may select either version ++ * 2 of the GNU General Public License ("GPL") or the BSD-3-Clause license ++ * ("BSD-3-Clause"). The GPL is included in the COPYING file accompanying the ++ * SOFTWARE. The BSD License is copied below. ++ * ++ * BSD-3-Clause License: ++ * Copyright (c) 2012-2016 Synopsys, Inc. and/or its affiliates. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright notice, ++ * this list of conditions, and the following disclaimer, without ++ * modification. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * 3. The names of the above-listed copyright holders may not be used to ++ * endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "nisttrng_hw.h" ++#include "nisttrng.h" ++ ++/* Wait functions */ ++static int nisttrng_wait_on_(struct nist_trng_state *state, u32 mask) ++{ ++ u32 tmp; ++ int t; ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ISTAT); ++ } while (!(tmp & (mask | NIST_TRNG_REG_ISTAT_ALARMS)) && --t); ++ ++ if (tmp & NIST_TRNG_REG_ISTAT_ALARMS) ++ return nisttrng_get_alarms(state); ++ ++ if (t) { ++ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, mask); ++ return CRYPTO_OK; ++ ++ } else { ++ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", ++ (unsigned long)tmp); ++ return CRYPTO_TIMEOUT; ++ } ++} /* nisttrng_wait_on_ */ ++ ++int nisttrng_wait_on_done(struct nist_trng_state *state) ++{ ++ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_DONE); ++} /* nisttrng_wait_on_done */ ++EXPORT_SYMBOL(nisttrng_wait_on_done); ++ ++int nisttrng_wait_on_noise_rdy(struct nist_trng_state *state) ++{ ++ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_NOISE_RDY); ++} /* nisttrng_wait_on_noise_rdy */ ++ ++static int nisttrng_wait_on_zeroize(struct nist_trng_state *state) ++{ ++ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_ZEROIZE); ++} /* nisttrng_wait_on_zeroize */ ++ ++static int nisttrng_wait_on_kat_completed(struct nist_trng_state *state) ++{ ++ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_KAT_COMPLETE); ++} /* nisttrng_wait_on_kat_completed */ ++ ++int nisttrng_wait_on_busy(struct nist_trng_state *state) ++{ ++ u32 tmp, t; ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); ++ } while ((tmp & NIST_TRNG_REG_STAT_BUSY) && --t); ++ ++ if (t) ++ return CRYPTO_OK; ++ ++ SYNHW_PRINT("wait_on_busy: failed timeout: %08lx\n", ++ (unsigned long)tmp); ++ return CRYPTO_TIMEOUT; ++} /* nisttrng_wait_on_busy */ ++EXPORT_SYMBOL(nisttrng_wait_on_busy); ++ ++/* Read and return alarm. Zeroize if there is an alarm*/ ++int nisttrng_get_alarms(struct nist_trng_state *state) ++{ ++ u32 tmp; ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ISTAT); ++ if (tmp & NIST_TRNG_REG_ISTAT_ALARMS) { ++ // alarm happened ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ALARM); ++ DEBUG("Received alarm: %lx\n", (unsigned long)tmp); ++ // clear istat ++ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, ++ NIST_TRNG_REG_ISTAT_ALARMS); ++ pdu_io_write32(state->base + NIST_TRNG_REG_ALARM, 0x1F); ++ state->status.alarm_code = tmp & 0x1F; ++ ++ /* zeroize if there was an alarm */ ++ if (state->status.alarm_code != ++ NIST_TRNG_REG_ALARM_FAILED_TEST_ID_OK) { ++ nisttrng_zeroize(state); ++ } ++ } else { ++ state->status.alarm_code = 0; ++ } ++ ++ if (state->status.alarm_code) ++ return CRYPTO_FATAL; ++ else ++ return CRYPTO_OK; ++} /* nisttrng_get_alarms */ ++EXPORT_SYMBOL(nisttrng_get_alarms); ++ ++/* Reset reminder and alarm counters */ ++int nisttrng_reset_counters(struct nist_trng_state *state) ++{ ++ state->counters.bits_per_req_left = state->counters.max_bits_per_req; ++ state->counters.req_per_seed_left = state->counters.max_req_per_seed; ++ ++ return 0; ++} /* nisttrng_reset_counters */ ++EXPORT_SYMBOL(nisttrng_reset_counters); ++ ++/* When a zeroize happens some of the struct objects should reset */ ++int nisttrng_reset_state(struct nist_trng_state *state) ++{ ++ nisttrng_reset_counters(state); ++ state->status.pad_ps_addin = 0; ++ state->status.current_state = NIST_TRNG_STATE_UNINSTANTIATE; ++ ++ return 0; ++} /* nisttrng_reset_state */ ++ ++/* ---------- Set field APIs ---------- */ ++ ++/* ++ * Sets the security strength of the DRBG instance. ++ * > req_sec_strength has to be an integer. The API chooses one of SEC_STRNT_AES128 or SEC_STRNT_AES256 as follows: ++ * 0 < req_sec_strength <= 128 --> security strength = SEC_STRNT_AES128 ++ * 128 < req_sec_strength <= 256 --> security strength = SEC_STRNT_AES256 ++ * else --> Invalid security strength ++ * > If the DRBG is instantiated, a new security strength change request with greater security strength will return error. ++ */ ++int nisttrng_set_sec_strength(struct nist_trng_state *state, int req_sec_strength) ++{ ++ int err; ++ u32 tmp; ++ enum nisttrng_sec_strength chosen_sec_strength; ++ ++ DEBUG(">> %s: security strength = %i\n", __func__, ++ req_sec_strength); ++ ++ /* choose the security strength */ ++ /* set the security strength to the lowest security strength greater or equal to the req_sec_strenght from the set {128, 256} */ ++ if (REQ_SEC_STRENGTH_IS_VALID(req_sec_strength)) { ++ if (req_sec_strength > 0 && req_sec_strength <= 128) { ++ chosen_sec_strength = SEC_STRNT_AES128; ++ ++ } else if (((req_sec_strength > 128) && ++ (req_sec_strength <= 256)) && ++ (state->config.features.drbg_arch == AES256)) { ++ chosen_sec_strength = SEC_STRNT_AES256; ++ ++ } else { /* should not get here, because we have already checked the validity */ ++ DEBUG("Invalid security strength\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ } else { ++ DEBUG("Invalid security strength\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ DEBUG("chosen security strength = %u\n", chosen_sec_strength); ++ ++ /* set the security strenght - at this point security strength is validated and converted */ ++ if (DRBG_INSTANTIATED(state->status.current_state) && ++ chosen_sec_strength != state->status.sec_strength) { ++ /* security strength can only change when the DRBG is not instantiated. */ ++ /* if the new security strength is less that what the DRBG is instantiated with, accept it, but don't change in HW. If it's more, return error */ ++ if (chosen_sec_strength < state->status.sec_strength) { ++ DEBUG("Lowering the security strength. DRBG is already instantiated.\n"); ++ state->status.pad_ps_addin = 4; ++ state->status.sec_strength = chosen_sec_strength; ++ ++ } else { ++ state->status.pad_ps_addin = 0; ++ DEBUG("Cannot select a higher security strenght once the DRBG is instantiated\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ } else { ++ DEBUG("Updating the security strength.\n"); ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); ++ tmp = NIST_TRNG_REG_MODE_SET_SEC_ALG(tmp, chosen_sec_strength); ++ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++ ++ state->status.pad_ps_addin = 0; ++ state->status.sec_strength = chosen_sec_strength; ++ } ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_sec_strength */ ++EXPORT_SYMBOL(nisttrng_set_sec_strength); ++ ++/* ++ * Sets the ADDIN_PRESENT field of the MODE register according to the addin_present input. ++ */ ++int nisttrng_set_addin_present(struct nist_trng_state *state, int addin_present) ++{ ++ u32 tmp; ++ ++ DEBUG(">> %s, adding_present = %u\n", __func__, ++ addin_present); ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); ++ tmp = NIST_TRNG_REG_MODE_SET_ADDIN_PRESENT(tmp, addin_present); ++ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++ ++ DEBUG("--- Return %s, err = %i\n", __func__, 0); ++ return 0; ++} /* nisttrng_set_addin_present */ ++EXPORT_SYMBOL(nisttrng_set_addin_present); ++ ++/* ++ * Sets the PRED_RESIST field of the MODE register according to the pred_resist input. ++ * > If the DRBG is instantiated with prediction resistance of 0, and a change to the prediction resistance of 1 is requested, ++ * the API will return an error. ++ */ ++int nisttrng_set_pred_resist(struct nist_trng_state *state, int pred_resist) ++{ ++ int err; ++ u32 tmp; ++ ++ DEBUG(">> %s: pred_resist = %u\n", __func__, pred_resist); ++ ++ /* if DRBG is instantiated, prediction resistance can only change from 1 to 0 and not vice versa. This is a NIST requirement. */ ++ if (DRBG_INSTANTIATED(state->status.current_state) && pred_resist && ++ !state->status.pred_resist) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); ++ tmp = NIST_TRNG_REG_MODE_SET_PRED_RESIST(tmp, pred_resist); ++ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++ ++ state->status.pred_resist = pred_resist; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_pred_resist */ ++EXPORT_SYMBOL(nisttrng_set_pred_resist); ++ ++/* ++ * Puts the NIST_TRNG in either the SECURE or PROMISCUOUS mode. ++ * > A value of 1 for secure_mode puts the core in the SECURE mode and a value of 0 puts it in the PROMISCUOUS mode. ++ * > Any change to the secure mode of the NIST_TRNG will result in a complete zeroize, and will set the seeding mode to self-seeding. ++ * A zeroize will not destroy the programmed mode and ALARM register value. ++ * It keeps the programmed mode to avoid re-programming. ++ * It also, maintains the ALARM register value, so that the user can read the value to understand the reason of the occurred alarm. ++ */ ++int nisttrng_set_secure_mode(struct nist_trng_state *state, int secure_mode) ++{ ++ int err; ++ u32 tmp; ++ int t; ++ ++ DEBUG(">> %s: secure_mode = %u\n", __func__, secure_mode); ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_SMODE); ++ tmp = NIST_TRNG_REG_SMODE_SET_SECURE_EN(tmp, secure_mode); ++ pdu_io_write32(state->base + NIST_TRNG_REG_SMODE, tmp); ++ ++ /* wait until STAT register indicates that the mode is applied */ ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); ++ } while ((NIST_TRNG_REG_STAT_GET_SECURE(tmp) != secure_mode) && --t); ++ ++ if (!t) { ++ err = CRYPTO_TIMEOUT; ++ goto ERR; ++ } ++ ++ /* if secure mode changes, a zeroize will happen in HW. */ ++ if (state->status.secure_mode != secure_mode) { ++ DEBUG("secure mode changed. zeroize happened. reset sw state\n"); ++ /* nonce mode goes back to default. */ ++ state->status.nonce_mode = 0; ++ /* reset the SW state */ ++ nisttrng_reset_state(state); ++ } ++ ++ state->status.secure_mode = secure_mode; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_secure_mode */ ++EXPORT_SYMBOL(nisttrng_set_secure_mode); ++ ++/* ++ * To change the seeding mode of the NIST_TRNG. ++ * > A value of 1 for nonce_mode will put the NIST_TRNG in the nonce seeding mode, which means that the seed will be provided by the user, ++ * unlike the noise or self-seeding mode (normal mode of operation) in which the seed is generated by the internal entropy source. ++ * > Any transition to or from the nonce mode will zeroize the NIST_TRNG. ++ */ ++int nisttrng_set_nonce_mode(struct nist_trng_state *state, int nonce_mode) ++{ ++ int err; ++ u32 tmp; ++ int t; ++ ++ DEBUG(">> %s: nonce_mode = %u\n", __func__, nonce_mode); ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_SMODE); ++ tmp = NIST_TRNG_REG_SMODE_SET_NONCE(tmp, nonce_mode); ++ pdu_io_write32(state->base + NIST_TRNG_REG_SMODE, tmp); ++ ++ /* wait until STAT register indicates that the mode is applied */ ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); ++ } while ((NIST_TRNG_REG_STAT_GET_NONCE(tmp) != nonce_mode) && --t); ++ ++ if (!t) { ++ err = CRYPTO_TIMEOUT; ++ goto ERR; ++ } ++ ++ /* if nonce mode changes, a zeroize will happen in HW. */ ++ if (state->status.nonce_mode != nonce_mode) { ++ DEBUG("nonce mode changed. zeroize happened. reset sw state\n"); ++ /* reset the SW state */ ++ nisttrng_reset_state(state); ++ } ++ ++ state->status.nonce_mode = nonce_mode; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_nonce_mode */ ++EXPORT_SYMBOL(nisttrng_set_nonce_mode); ++ ++/* ---------- Load data APIs ---------- */ ++/* ++ * Loads the additional input or personalization string into the NPA_DATAx registers. ++ * > Loads the proper number of bits (256 or 384) according to the security strength stored in the state handle. ++ */ ++int nisttrng_load_ps_addin(struct nist_trng_state *state, void *input_str) ++{ ++ int err; ++ int i, j; ++ int str_size; ++ ++ DEBUG(">> %s starts...\n", __func__); ++ ++ /* return error if the pointer is NULL */ ++ if (!input_str) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* calculate the length based on the security strength */ ++ if (state->status.sec_strength == SEC_STRNT_AES128) ++ str_size = 8; /* 256/32 */ ++ else if (state->status.sec_strength == SEC_STRNT_AES256) ++ str_size = 12; /* 384/32 */ ++ ++ for (i = 0; i < str_size; i++) { ++ pdu_io_write32(state->base + NIST_TRNG_REG_NPA_DATA0 + i, ++ ((u32 *)input_str)[i]); ++ } ++ ++ j = str_size + state->status.pad_ps_addin; ++ /* if security strength is lowered after the DRBG is instantiated, pad PS and ADDIN with 0 at the MSB side */ ++ DEBUG("pad NPA_DATA with %u zeros at the MSB side\n", ++ state->status.pad_ps_addin); ++ for (i = str_size; i < j; i++) ++ pdu_io_write32(state->base + NIST_TRNG_REG_NPA_DATA0 + i, 0); ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_load_ps_addin */ ++EXPORT_SYMBOL(nisttrng_load_ps_addin); ++ ++/* ---------- Command APIs ---------- */ ++/* ++ * Provides entropy and is used in both nonce and noise (self) seeding modes of operation: ++ * > If the NIST_TRNG is in the nonce mode, entropy must be provided by the user; otherwise (in the self-seeding mode) entropy will be generated by the internal entropy source of the NIST_TRNG. ++ * > In the noise mode, calling the API will initiate a seeding command. Depending on the programmed security strength, a 256 or 384-bit seed will be generated. ++ * > Inputs 2 and 3 are only used when the core is in the nonce mode. ++ * > In the nonce mode, the NIST_TRNG can be seeded either through 2 or 3 blocks of 512-bit nonce values which are passed to the internal derivation function to increase the entropy, ++ * or it can be seeded by a 256 or 384-bit nonce written directly into the SEEDx registers. ++ * Passing a value of 1 to nonce_operation selects the former scenario and a value of 0 selects the latter. ++ * > The input_nonce pointer must point to a memory location with a sufficient number of initialized bits. ++ * > Table below shows the required number of bits depending on the nonce_operation and the security strength values. ++ * nonce_operation | Security Strength | Bit length requirement ++ * ------------------------------------------------------------------------------------------ ++ * 1 (using the Derivation Function) | SEC_STRNT_AES128 | 2x512 = 1024 ++ * 1 (using the Derivation Function) | SEC_STRNT_AES256 | 3x512 = 1536 ++ * 0 (loading the seed into SEEDx) | SEC_STRNT_AES128 | 256 ++ * 0 (loading the seed into SEEDx) | SEC_STRNT_AES256 | 384 ++ * > Generated entropy is secret information held securely within the HW and remains inaccessible to the user, unless the HW core is in the PROMISCUOUS mode. ++ */ ++int nisttrng_get_entropy_input(struct nist_trng_state *state, void *input_nonce, ++ int nonce_operation) ++{ ++ int err; ++ int nonce_ld_cntr = 0; ++ int i, j; ++ ++ DEBUG(">> %s: seeding mode = %s, nonce_operation = %u\n", __func__, ++ (state->status.nonce_mode ? "Nonce" : "Noise"), nonce_operation); ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* --- Seeding --- */ ++ if (state->status.nonce_mode) { /* --- nonce mode --- */ ++ if (!input_nonce) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ nonce_ld_cntr = 0; ++ ++ if (state->status.sec_strength == SEC_STRNT_AES128) ++ nonce_ld_cntr = 2; ++ else if (state->status.sec_strength == SEC_STRNT_AES256) ++ nonce_ld_cntr = 3; ++ ++ if (nonce_operation) { /* load the noise inside NPA_DATAx register and issue gen_nonce command */ ++ for (i = 0; i < nonce_ld_cntr; i++) { ++ /* load the nonoce */ ++ for (j = 0; j < 16; j++) { ++ pdu_io_write32(state->base + ++ NIST_TRNG_REG_NPA_DATA0 + j, ++ ((u32 *)input_nonce)[16 * i + j]); ++ } ++ ++ /* issue the command and wait on done */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_GEN_NONCE); ++ ++ if (nisttrng_wait_on_done(state)) { ++ err = CRYPTO_FATAL; ++ goto ERR; ++ }; ++ } ++ ++ } else { ++ /* load the nonoce */ ++ for (i = 0; i < 4 * nonce_ld_cntr; i++) { ++ pdu_io_write32(state->base + NIST_TRNG_REG_SEED0 + i, ++ ((u32 *)input_nonce)[i]); ++ } ++ } ++ } else { /* --- noise mode --- */ ++ /* issue the command and wait on done */ ++ DEBUG("issue the Gen_Noise command\n"); ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_GEN_NOISE); ++ ++ if (nisttrng_wait_on_done(state)) { ++ err = CRYPTO_FATAL; ++ goto ERR; ++ }; ++ } ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_get_entropy_input */ ++EXPORT_SYMBOL(nisttrng_get_entropy_input); ++ ++/* ++ * Generate Function: ++ * > The Generate function in NIST_TRNG HW is broken down into 3 steps: Refresh_Addin, Gen_Random and Advance_State. ++ * nisttrng_generate incorporates all these steps and some extra checks into one simple API. ++ * > There is one API for each step, below || ++ * \/ ++ */ ++/* ++ * Generate Part 1 - Refresh_Addin: Additional input string is used to add to the HW state entropy. ++ * > This API calls nisttrng_set_addin_present to set the ADDIN_PRESENT field of the MODE register to 1. ++ * > Then it loads the additional input provided by addin_str pointer into the NPA_DATAx by calling the nisttrng_load_ps_addin. ++ * > Then, it issues a Refresh_Addin command to the HW. ++ * > If the addin_str pointer is NULL, the API will return error. ++ */ ++int nisttrng_refresh_addin(struct nist_trng_state *state, void *addin_str) ++{ ++ int err; ++ ++ DEBUG(">> %s starts...\n", __func__); ++ ++ /* if the DRBG is not intantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* This API should not be called with a NULL additional input string */ ++ if (!addin_str) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* set the ADDIN_PRESENT field of the MODE register to 1 */ ++ err = nisttrng_set_addin_present(state, 1); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_load_ps_addin(state, addin_str); ++ if (err) ++ goto ERR; ++ ++ /* execute the command and wait on done*/ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_REFRESH_ADDIN); ++ ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; ++ ++ err = 0; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_refresh_addin */ ++EXPORT_SYMBOL(nisttrng_refresh_addin); ++ ++/* ++ * Generate Part 2 - Gen_Random: generates the requested number of bits. ++ * > This API issues the Gen_Random command to the HW as many times as indicated by req_num_bytes to generate the requested number of bits. ++ * > If the requested number of bits (i.e. 128×req_num_blks) is more than the maximum value specified by max_bits_per_req, the API will return error. ++ * > Random bits will be returned in random_bits. ++ */ ++int nisttrng_gen_random(struct nist_trng_state *state, void *random_bits, ++ unsigned long req_num_bytes) ++{ ++ int err; ++ int i, j; ++ u32 tmp; ++ unsigned int remained_bytes; ++ unsigned long req_num_blks; ++ ++ DEBUG(">> %s: req_num_bytes = %lu\n", __func__, req_num_bytes); ++ ++ /* if the DRBG is not intantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* requested number of bits has to be less that the programmed maximum */ ++ if ((req_num_bytes * 8) > state->counters.max_bits_per_req) { ++ DEBUG("requested number of bits (%lu) is larger than the set maximum (%lu)\n", ++ (req_num_bytes * 8), state->counters.max_bits_per_req); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ DEBUG("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* loop on generate to get the requested number of bits. Each generate gives NIST_TRNG_RAND_BLK_SIZE_BITS bits. */ ++ req_num_blks = ++ ((req_num_bytes * 8) % NIST_TRNG_RAND_BLK_SIZE_BITS) ? ++ (((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS) + ++ 1) : ++ ((req_num_bytes * 8) / NIST_TRNG_RAND_BLK_SIZE_BITS); ++ ++ for (i = 0; i < req_num_blks; i++) { ++ /* issue gen_random and wait on done */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_GEN_RANDOM); ++ ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; ++ ++ /* read the generated random number block and store */ ++ for (j = 0; j < (NIST_TRNG_RAND_BLK_SIZE_BITS / 32); j++) { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_RAND0 + j); ++ /* copy to random_bits byte-by-byte, until req_num_bytes are copied */ ++ remained_bytes = req_num_bytes - ++ (i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4); ++ if (remained_bytes > 4) { ++ memcpy(random_bits + ++ i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, 4); ++ ++ /* decrement the bits counter and return error if generated more than the maximum*/ ++ state->counters.bits_per_req_left = ++ state->counters.bits_per_req_left - ++ 4 * 8; ++ ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ } else { ++ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, remained_bytes); ++ ++ /* decrement the bits counter and return error if generated more than the maximum*/ ++ state->counters.bits_per_req_left = ++ state->counters.bits_per_req_left - ++ remained_bytes * 8; ++ ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ break; ++ } ++ } ++ } ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_gen_random */ ++EXPORT_SYMBOL(nisttrng_gen_random); ++ ++/* ++ * Generate Part 3 - Advance the state: advances the state of the DRBG. ++ * > This API issues the Advance_State command to the HW. ++ * > Then it updates the counter for the number of generate requests per seed. ++ * > The counter must be checked every time before starting the Generate process and a reseed must be issued if the limit is reached. This check is incorporated inside nisttrng_generate API. ++ * > Note that we don't have to provide additional input again for this API, because if it had been provided in refresh_addin stage, HW will lock the NPA_DATAx, so it will be still available ++ */ ++int nisttrng_advance_state(struct nist_trng_state *state) ++{ ++ int err; ++ ++ DEBUG(">> %s starts...\n", __func__); ++ ++ /* if the DRBG is not intantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; ++ ++ /* issue advance_state and wait on done */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_ADVANCE_STATE); ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; ++ ++ /* generate is finished, reset the bits_per_req_left counter */ ++ state->counters.bits_per_req_left = state->counters.max_bits_per_req; ++ ++ --state->counters.req_per_seed_left; ++ if (state->counters.req_per_seed_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } /* just a check */ ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_advance_state */ ++ ++int nisttrng_check_seed_lifetime(struct nist_trng_state *state) ++{ ++ int err; ++ ++ if (state->counters.req_per_seed_left <= 0) { ++ DEBUG("maximum number of requests per seed is reached\n"); ++ err = CRYPTO_RESEED_REQUIRED; ++ goto ERR; ++ } ++ ++ err = CRYPTO_OK; ++ERR: ++ return err; ++} ++EXPORT_SYMBOL(nisttrng_advance_state); ++ ++/* ++ * Perform Known Answer Test ++ * > The NIST_TRNG can perform a KAT on the DRBG and the derivation function inside the entropy source. There are also two different vectors available to do the KAT. ++ * > The kat_sel input selects whether the KAT should be performed on the DRBG or the derivation function. ++ * > The kat_vec input chooses the KAT vector. ++ * > Selections are done by writing the values to the MODE register. ++ * > If the KAT fails, the API returns error. ++ */ ++int nisttrng_kat(struct nist_trng_state *state, int kat_sel, int kat_vec) ++{ ++ int err; ++ u32 tmp; ++ ++ DEBUG(">> %s: kat_sel = %u, kat_vec = %u\n", __func__, ++ kat_sel, kat_vec); ++ ++ /* set KAT_SEL and KAT_VEC */ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_MODE); ++ tmp = NIST_TRNG_REG_MODE_SET_KAT_SEL(tmp, kat_sel); ++ tmp = NIST_TRNG_REG_MODE_SET_KAT_VEC(tmp, kat_vec); ++ pdu_io_write32(state->base + NIST_TRNG_REG_MODE, tmp); ++ ++ /* issue the command and wait on kat_completed */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_KAT); ++ ++ err = nisttrng_wait_on_kat_completed(state); ++ if (err) ++ goto ERR; ++ ++ /* check for alarms */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_kat */ ++EXPORT_SYMBOL(nisttrng_kat); ++ ++/* ++ * Performs a full KAT with all four combinations of the kat_sel and kat_vec ++ * > If any of the KAT fails, the API returns error. ++ */ ++int nisttrng_full_kat(struct nist_trng_state *state) ++{ ++ int err; ++ ++ DEBUG(">> %s starts...\n", __func__); ++ ++ /* SEL = 0, Vec = 0 */ ++ err = nisttrng_kat(state, 0, 0); ++ if (err) ++ goto ERR; ++ ++ /* SEL = 0, Vec = 1 */ ++ err = nisttrng_kat(state, 0, 1); ++ if (err) ++ goto ERR; ++ ++ /* SEL = 1, Vec = 0 */ ++ err = nisttrng_kat(state, 1, 0); ++ if (err) ++ goto ERR; ++ ++ /* SEL = 1, Vec = 1 */ ++ err = nisttrng_kat(state, 1, 1); ++ if (err) ++ goto ERR; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_full_kat */ ++EXPORT_SYMBOL(nisttrng_full_kat); ++ ++/* ++ * max_bits_per_req reminder initialized by nisttrng_init can change using this API. ++ * > If this API is called when the DRBG is instantiated, an error will be returned. ++ * > If the requested maximum is more than the standard's limit (determinded by NIST_TRNG_DFLT_MAX_BITS_PER_REQ), the API will return an error. ++ */ ++int nisttrng_set_reminder_max_bits_per_req(struct nist_trng_state *state, ++ unsigned long max_bits_per_req) ++{ ++ int err; ++ ++ DEBUG(">> %s: %lu\n", __func__, max_bits_per_req); ++ ++ /* if the DRBG is instantiated, cannot change the value */ ++ if (DRBG_INSTANTIATED(state->status.current_state)) { ++ DEBUG("cannot change the reminder value when DRBG is already instantiated\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* requested value cannot be more than NIST's limit */ ++ if (max_bits_per_req > NIST_DFLT_MAX_BITS_PER_REQ) { ++ DEBUG("requested max_bits_per_req is more than standard's limit\n"); ++ err = CRYPTO_INVALID_ARGUMENT; ++ goto ERR; ++ } ++ ++ state->counters.max_bits_per_req = max_bits_per_req; ++ state->counters.bits_per_req_left = max_bits_per_req; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++EXPORT_SYMBOL(nisttrng_set_reminder_max_bits_per_req); ++ ++/* ++ * max_req_per_seed reminder initialized by nisttrng_init can change using this API. ++ * > If this API is called when the DRBG is instantiated, an error will be returned. ++ * > If the requested maximum is more than the standard's limit (determinded by NIST_TRNG_DFLT_MAX_REQ_PER_SEED), the API will return an error. ++ */ ++int nisttrng_set_reminder_max_req_per_seed(struct nist_trng_state *state, ++ unsigned long long max_req_per_seed) ++{ ++ int err; ++ ++ DEBUG(">> %s: %llu\n", __func__, max_req_per_seed); ++ ++ /* if the DRBG is instantiated, cannot change the value */ ++ if (DRBG_INSTANTIATED(state->status.current_state)) { ++ DEBUG("cannot change the reminder value when DRBG is already instantiated\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ ++ /* requested value cannot be more than NIST's limit */ ++ if (max_req_per_seed > NIST_DFLT_MAX_REQ_PER_SEED) { ++ DEBUG("requested max_req_per_seed is more than standard's limit\n"); ++ err = CRYPTO_INVALID_ARGUMENT; ++ goto ERR; ++ } ++ ++ state->counters.max_req_per_seed = max_req_per_seed; ++ state->counters.req_per_seed_left = max_req_per_seed; ++ ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++EXPORT_SYMBOL(nisttrng_set_reminder_max_req_per_seed); ++ ++/* ++ * Zeroize command ++ * > A zeroize will not destroy the programmed mode and ALARM register value. ++ * It keeps the programmed mode to avoid re-programming. ++ * It also, maintains the ALARM register value, so that the user can read the value to understand the reason of the occurred alarm. ++ */ ++int nisttrng_zeroize(struct nist_trng_state *state) ++{ ++ int err; ++ ++ DEBUG(">> %s: zeroize the core\n", __func__); ++ ++ /* issue zeroize command */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_ZEROIZE); ++ ++ /* wait on zeroize done */ ++ err = nisttrng_wait_on_zeroize(state); ++ if (err) ++ goto ERR; ++ ++ /* reset the SW state */ ++ nisttrng_reset_state(state); ++ ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_UNINSTANTIATE; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_zeroize */ ++EXPORT_SYMBOL(nisttrng_zeroize); ++ ++int nisttrng_rnc(struct nist_trng_state *state, int rnc_ctrl_cmd) ++{ ++ int err = 0; ++ u32 tmp; ++ ++ DEBUG(">> %s cmd %d\n", __func__, rnc_ctrl_cmd); ++ ++ if (rnc_ctrl_cmd > NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_FINISH_TO_IDLE) { ++ DEBUG(">> Invalid cmd %d\n", rnc_ctrl_cmd); ++ err = -1; ++ goto ERR; ++ } ++ ++ if (!state->config.build_cfg0.edu_present) { ++ DEBUG(">> edu not present\n"); ++ err = -1; ++ goto ERR; ++ } ++ ++ pdu_io_write32(state->base + NIST_TRNG_EDU_RNC_CTRL, rnc_ctrl_cmd); ++ if (rnc_ctrl_cmd == NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE) { ++ // wait till rnc is enabled ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); ++ } while (!NIST_TRNG_EDU_STAT_RNC_ENABLED(tmp)); ++ ++ state->status.edu_vstat.rnc_enabled = 1; ++ ++ } else { ++ // wait till rnc is idle (disabled) ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); ++ } while (NIST_TRNG_EDU_STAT_RNC_ENABLED(tmp)); ++ ++ state->status.edu_vstat.rnc_enabled = 0; ++ } ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++EXPORT_SYMBOL(nisttrng_rnc); ++ ++int nisttrng_wait_fifo_full(struct nist_trng_state *state) ++{ ++ int err = 0; ++ u32 tmp, t; ++ ++ t = NIST_TRNG_RETRY_MAX; ++ ++ DEBUG(">> %s starts...\n", __func__); ++ ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); ++ } while ((!NIST_TRNG_EDU_STAT_FIFO_FULL(tmp)) && --t); ++ ++ if (t) { ++ err = CRYPTO_OK; ++ } else { ++ DEBUG("wait_on_fifo_full: failed timeout: %08lx\n", ++ (unsigned long)tmp); ++ err = CRYPTO_TIMEOUT; ++ goto ERR; ++ } ++ ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} +diff --git a/drivers/i3c/mctp/Kconfig b/drivers/i3c/mctp/Kconfig +--- a/drivers/i3c/mctp/Kconfig 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/i3c/mctp/Kconfig 2026-09-09 15:51:42.670269018 +0000 +@@ -0,0 +1,23 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config I3C_MCTP ++ tristate "I3C Controller MCTP driver" ++ depends on I3C ++help ++ Say yes here to enable the I3C MCTP driver for I3C HW that is ++ configured as an I3C Controller Device on the I3C Bus. ++ ++config I3C_MCTP_HDR_DDR ++ bool "transfer with HDR-DDR mode" ++ depends on I3C_MCTP ++ default n ++ help ++ Say yes here to use the HDR-DDR mode as default to transfer data if ++ the device support it. ++ ++config I3C_TARGET_MCTP ++ tristate "I3C Target MCTP driver" ++ depends on I3C ++ select CRC8 ++help ++ Say yes here to enable the I3C MCTP driver for I3C HW that is ++ configured as an I3C Target Device on the I3C Bus. +diff --git a/drivers/i3c/mctp/Makefile b/drivers/i3c/mctp/Makefile +--- a/drivers/i3c/mctp/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/i3c/mctp/Makefile 2026-09-09 15:51:42.670269018 +0000 +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++obj-$(CONFIG_I3C_MCTP) += i3c-mctp.o ++obj-$(CONFIG_I3C_TARGET_MCTP) += i3c-target-mctp.o +diff --git a/drivers/i3c/mctp/i3c-mctp.c b/drivers/i3c/mctp/i3c-mctp.c +--- a/drivers/i3c/mctp/i3c-mctp.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/i3c/mctp/i3c-mctp.c 2026-09-09 15:51:42.670269018 +0000 +@@ -0,0 +1,697 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (C) 2022 Intel Corporation.*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#define I3C_MCTP_MINORS 32 ++#define CCC_DEVICE_STATUS_PENDING_INTR(x) (((x) & GENMASK(3, 0)) >> 0) ++#define POLLING_TIMEOUT_MS 50 ++#define MCTP_INTERRUPT_NUMBER 1 ++#define RX_RING_COUNT 16 ++#define I3C_MCTP_MIN_TRANSFER_SIZE 69 ++#define I3C_MCTP_IBI_PAYLOAD_SIZE 2 ++ ++struct i3c_mctp { ++ struct i3c_device *i3c; ++ struct cdev cdev; ++ struct device *dev; ++ struct delayed_work polling_work; ++ struct platform_device *i3c_peci; ++ int id; ++ /* ++ * Restrict an access to the /dev descriptor to one ++ * user at a time. ++ */ ++ spinlock_t device_file_lock; ++ int device_open; ++ /* Currently only one userspace client is supported */ ++ struct i3c_mctp_client *default_client; ++ struct i3c_mctp_client *peci_client; ++ u16 max_read_len; ++ u16 max_write_len; ++}; ++ ++struct i3c_mctp_client { ++ struct i3c_mctp *priv; ++ struct ptr_ring rx_queue; ++ wait_queue_head_t wait_queue; ++}; ++ ++static struct class *i3c_mctp_class; ++static dev_t i3c_mctp_devt; ++static DEFINE_IDA(i3c_mctp_ida); ++ ++static struct kmem_cache *packet_cache; ++ ++/** ++ * i3c_mctp_packet_alloc() - allocates i3c_mctp_packet ++ * ++ * @flags: the type of memory to allocate ++ * ++ * Allocates i3c_mctp_packet via slab allocation ++ * Return: pointer to the packet, NULL if some error occurred ++ */ ++void *i3c_mctp_packet_alloc(gfp_t flags) ++{ ++ return kmem_cache_alloc(packet_cache, flags); ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_packet_alloc); ++ ++/** ++ * i3c_mctp_packet_free() - frees i3c_mctp_packet ++ * ++ * @packet: pointer to the packet which should be freed ++ * ++ * Frees i3c_mctp_packet previously allocated via slab allocation ++ */ ++void i3c_mctp_packet_free(void *packet) ++{ ++ kmem_cache_free(packet_cache, packet); ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_packet_free); ++ ++static void i3c_mctp_client_free(struct i3c_mctp_client *client) ++{ ++ ptr_ring_cleanup(&client->rx_queue, &i3c_mctp_packet_free); ++ ++ kfree(client); ++} ++ ++static struct i3c_mctp_client *i3c_mctp_client_alloc(struct i3c_mctp *priv) ++{ ++ struct i3c_mctp_client *client; ++ int ret; ++ ++ client = kzalloc(sizeof(*client), GFP_KERNEL); ++ if (!client) ++ goto out; ++ ++ client->priv = priv; ++ ret = ptr_ring_init(&client->rx_queue, RX_RING_COUNT, GFP_KERNEL); ++ if (ret) ++ return ERR_PTR(ret); ++ init_waitqueue_head(&client->wait_queue); ++out: ++ return client; ++} ++ ++static struct i3c_mctp_client *i3c_mctp_find_client(struct i3c_mctp *priv, ++ struct i3c_mctp_packet *packet) ++{ ++ u8 *msg_hdr = (u8 *)packet->data.payload; ++ u8 mctp_type = msg_hdr[MCTP_MSG_HDR_MSG_TYPE_OFFSET]; ++ u16 vendor = (msg_hdr[MCTP_MSG_HDR_VENDOR_OFFSET] << 8 ++ | msg_hdr[MCTP_MSG_HDR_VENDOR_OFFSET + 1]); ++ u8 intel_msg_op_code = msg_hdr[MCTP_MSG_HDR_OPCODE_OFFSET]; ++ ++ if (priv->peci_client && mctp_type == MCTP_MSG_TYPE_VDM_PCI && ++ vendor == MCTP_VDM_PCI_INTEL_VENDOR_ID && intel_msg_op_code == MCTP_VDM_PCI_INTEL_PECI) ++ return priv->peci_client; ++ ++ return priv->default_client; ++} ++ ++static struct i3c_mctp_packet *i3c_mctp_read_packet(struct i3c_device *i3c) ++{ ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3c)); ++ struct i3c_mctp_packet *rx_packet; ++ struct i3c_priv_xfer xfers = { ++ .rnw = true, ++ }; ++ int ret; ++ ++ rx_packet = i3c_mctp_packet_alloc(GFP_KERNEL); ++ if (!rx_packet) ++ return ERR_PTR(-ENOMEM); ++ ++ rx_packet->size = I3C_MCTP_PACKET_SIZE; ++ xfers.len = rx_packet->size; ++ xfers.data.in = &rx_packet->data; ++ ++ /* Check against packet size + PEC byte to make sure that we always try to read max */ ++ if (priv->max_read_len != xfers.len + 1) { ++ dev_dbg(i3cdev_to_dev(i3c), "Length mismatch. MRL = %d, xfers.len = %d", ++ priv->max_read_len, xfers.len); ++ i3c_mctp_packet_free(rx_packet); ++ return ERR_PTR(-EINVAL); ++ } ++ if (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && ++ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { ++ struct i3c_hdr_cmd cmds; ++ ++ cmds.mode = I3C_HDR_DDR; ++ cmds.code = 0x80; ++ cmds.ndatawords = DIV_ROUND_UP(rx_packet->size, 2); ++ cmds.data.in = &rx_packet->data; ++ ret = i3c_device_send_hdr_cmds(i3c, &cmds, 1); ++ if (!ret) ++ rx_packet->size = cmds.ndatawords; ++ } else { ++ ret = i3c_device_do_priv_xfers(i3c, &xfers, 1); ++ if (!ret) ++ rx_packet->size = xfers.len; ++ } ++ if (ret) { ++ i3c_mctp_packet_free(rx_packet); ++ return ERR_PTR(ret); ++ } ++ ++ return rx_packet; ++} ++ ++static void i3c_mctp_dispatch_packet(struct i3c_mctp *priv, struct i3c_mctp_packet *packet) ++{ ++ struct i3c_mctp_client *client = i3c_mctp_find_client(priv, packet); ++ int ret; ++ ++ ret = ptr_ring_produce(&client->rx_queue, packet); ++ if (ret) ++ i3c_mctp_packet_free(packet); ++ else ++ wake_up_all(&client->wait_queue); ++} ++ ++static void i3c_mctp_polling_work(struct work_struct *work) ++{ ++ struct i3c_mctp *priv = container_of(to_delayed_work(work), struct i3c_mctp, polling_work); ++ struct i3c_device *i3cdev = priv->i3c; ++ struct i3c_mctp_packet *rx_packet; ++ struct i3c_device_info info; ++ int ret; ++ ++ i3c_device_get_info(i3cdev, &info); ++ ret = i3c_device_getstatus_ccc(i3cdev, &info); ++ if (ret) ++ return; ++ ++ if (CCC_DEVICE_STATUS_PENDING_INTR(info.status) != MCTP_INTERRUPT_NUMBER) ++ return; ++ ++ rx_packet = i3c_mctp_read_packet(i3cdev); ++ if (IS_ERR(rx_packet)) ++ goto out; ++ ++ i3c_mctp_dispatch_packet(priv, rx_packet); ++out: ++ schedule_delayed_work(&priv->polling_work, msecs_to_jiffies(POLLING_TIMEOUT_MS)); ++} ++ ++static ssize_t i3c_mctp_write(struct file *file, const char __user *buf, size_t count, ++ loff_t *f_pos) ++{ ++ struct i3c_mctp *priv = file->private_data; ++ struct i3c_device *i3c = priv->i3c; ++ struct i3c_priv_xfer xfers = { ++ .rnw = false, ++ .len = count, ++ }; ++ u8 *data; ++ int ret; ++ ++ /* ++ * Check against packet size + PEC byte ++ * to not send more data than it was set in the probe ++ */ ++ if (priv->max_write_len < xfers.len + 1) { ++ dev_dbg(i3cdev_to_dev(i3c), "Length mismatch. MWL = %d, xfers.len = %d", ++ priv->max_write_len, xfers.len); ++ return -EINVAL; ++ } ++ ++ data = memdup_user(buf, count); ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ if (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && ++ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { ++ struct i3c_hdr_cmd cmds; ++ ++ cmds.mode = I3C_HDR_DDR; ++ cmds.code = 0; ++ cmds.ndatawords = DIV_ROUND_UP(count, 2); ++ cmds.data.out = data; ++ ret = i3c_device_send_hdr_cmds(i3c, &cmds, 1); ++ } else { ++ xfers.data.out = data; ++ ++ ret = i3c_device_do_priv_xfers(i3c, &xfers, 1); ++ } ++ kfree(data); ++ return ret ?: count; ++} ++ ++static ssize_t i3c_mctp_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) ++{ ++ struct i3c_mctp *priv = file->private_data; ++ struct i3c_mctp_client *client = priv->default_client; ++ struct i3c_mctp_packet *rx_packet; ++ ++ if (count > sizeof(rx_packet->data)) ++ count = sizeof(rx_packet->data); ++ ++ rx_packet = ptr_ring_consume(&client->rx_queue); ++ if (!rx_packet) ++ return -EAGAIN; ++ ++ if (count > rx_packet->size) ++ count = rx_packet->size; ++ ++ if (copy_to_user(buf, &rx_packet->data, count)) ++ return -EFAULT; ++ ++ i3c_mctp_packet_free(rx_packet); ++ ++ return count; ++} ++ ++static int i3c_mctp_open(struct inode *inode, struct file *file) ++{ ++ struct i3c_mctp *priv = container_of(inode->i_cdev, struct i3c_mctp, cdev); ++ ++ spin_lock(&priv->device_file_lock); ++ if (priv->device_open) { ++ spin_unlock(&priv->device_file_lock); ++ return -EBUSY; ++ } ++ priv->device_open++; ++ /* Discard all of the packet in the rx_queue */ ++ while (ptr_ring_consume(&priv->default_client->rx_queue)) ++ ; ++ spin_unlock(&priv->device_file_lock); ++ ++ file->private_data = priv; ++ ++ return 0; ++} ++ ++static int i3c_mctp_release(struct inode *inode, struct file *file) ++{ ++ struct i3c_mctp *priv = file->private_data; ++ ++ spin_lock(&priv->device_file_lock); ++ priv->device_open--; ++ spin_unlock(&priv->device_file_lock); ++ ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static __poll_t i3c_mctp_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ struct i3c_mctp *priv = file->private_data; ++ __poll_t ret = 0; ++ ++ poll_wait(file, &priv->default_client->wait_queue, pt); ++ ++ if (__ptr_ring_peek(&priv->default_client->rx_queue)) ++ ret |= EPOLLIN; ++ ++ return ret; ++} ++ ++static const struct file_operations i3c_mctp_fops = { ++ .owner = THIS_MODULE, ++ .read = i3c_mctp_read, ++ .write = i3c_mctp_write, ++ .poll = i3c_mctp_poll, ++ .open = i3c_mctp_open, ++ .release = i3c_mctp_release, ++}; ++ ++/** ++ * i3c_mctp_add_peci_client() - registers PECI client ++ * @i3c: I3C device to get the PECI client for ++ * ++ * Return: pointer to PECI client, -ENOMEM - in case of client alloc fault ++ */ ++struct i3c_mctp_client *i3c_mctp_add_peci_client(struct i3c_device *i3c) ++{ ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3c)); ++ struct i3c_mctp_client *client; ++ ++ client = i3c_mctp_client_alloc(priv); ++ if (IS_ERR(client)) ++ return ERR_PTR(-ENOMEM); ++ ++ priv->peci_client = client; ++ ++ return priv->peci_client; ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_add_peci_client); ++ ++/** ++ * i3c_mctp_remove_peci_client() - un-registers PECI client ++ * @client: i3c_mctp_client to be freed ++ */ ++void i3c_mctp_remove_peci_client(struct i3c_mctp_client *client) ++{ ++ struct i3c_mctp *priv = client->priv; ++ ++ i3c_mctp_client_free(priv->peci_client); ++ ++ priv->peci_client = NULL; ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_remove_peci_client); ++ ++static struct i3c_mctp *i3c_mctp_alloc(struct i3c_device *i3c) ++{ ++ struct i3c_mctp *priv; ++ int id; ++ ++ priv = devm_kzalloc(i3cdev_to_dev(i3c), sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return ERR_PTR(-ENOMEM); ++ ++ id = ida_alloc(&i3c_mctp_ida, GFP_KERNEL); ++ if (id < 0) { ++ pr_err("i3c_mctp: no minor number available!\n"); ++ return ERR_PTR(id); ++ } ++ ++ priv->id = id; ++ priv->i3c = i3c; ++ ++ spin_lock_init(&priv->device_file_lock); ++ ++ return priv; ++} ++ ++static void i3c_mctp_ibi_handler(struct i3c_device *dev, const struct i3c_ibi_payload *payload) ++{ ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(dev)); ++ struct i3c_mctp_packet *rx_packet; ++ ++ rx_packet = i3c_mctp_read_packet(dev); ++ if (IS_ERR(rx_packet)) ++ return; ++ ++ i3c_mctp_dispatch_packet(priv, rx_packet); ++} ++ ++static int i3c_mctp_init(struct i3c_driver *drv) ++{ ++ int ret; ++ ++ packet_cache = kmem_cache_create_usercopy("mctp-i3c-packet", ++ sizeof(struct i3c_mctp_packet), 0, 0, 0, ++ sizeof(struct i3c_mctp_packet), NULL); ++ if (IS_ERR(packet_cache)) { ++ ret = PTR_ERR(packet_cache); ++ goto out; ++ } ++ ++ /* Dynamically request unused major number */ ++ ret = alloc_chrdev_region(&i3c_mctp_devt, 0, I3C_MCTP_MINORS, "i3c-mctp"); ++ if (ret) ++ goto out; ++ ++ /* Create a class to populate sysfs entries*/ ++ i3c_mctp_class = class_create("i3c-mctp"); ++ if (IS_ERR(i3c_mctp_class)) { ++ ret = PTR_ERR(i3c_mctp_class); ++ goto out_unreg_chrdev; ++ } ++ ++ i3c_driver_register(drv); ++ ++ return 0; ++ ++out_unreg_chrdev: ++ unregister_chrdev_region(i3c_mctp_devt, I3C_MCTP_MINORS); ++out: ++ pr_err("i3c_mctp: driver initialisation failed\n"); ++ return ret; ++} ++ ++static void i3c_mctp_free(struct i3c_driver *drv) ++{ ++ i3c_driver_unregister(drv); ++ class_destroy(i3c_mctp_class); ++ unregister_chrdev_region(i3c_mctp_devt, I3C_MCTP_MINORS); ++ kmem_cache_destroy(packet_cache); ++} ++ ++static int i3c_mctp_enable_ibi(struct i3c_device *i3cdev) ++{ ++ struct i3c_ibi_setup ibireq = { ++ .handler = i3c_mctp_ibi_handler, ++ .max_payload_len = 2, ++ .num_slots = 10, ++ }; ++ int ret; ++ ++ ret = i3c_device_request_ibi(i3cdev, &ibireq); ++ if (ret) ++ return ret; ++ ret = i3c_device_enable_ibi(i3cdev); ++ if (ret) ++ i3c_device_free_ibi(i3cdev); ++ ++ return ret; ++} ++ ++static void i3c_mctp_disable_ibi(struct i3c_device *i3cdev) ++{ ++ i3c_device_disable_ibi(i3cdev); ++ i3c_device_free_ibi(i3cdev); ++} ++ ++/** ++ * i3c_mctp_get_eid() - receive MCTP EID assigned to the device ++ * ++ * @client: client for the device to get the EID for ++ * @domain_id: requested domain ID ++ * @eid: pointer to store EID value ++ * ++ * Receive MCTP endpoint ID dynamically assigned by the MCTP Bus Owner ++ * Return: 0 in case of success, a negative error code otherwise. ++ */ ++int i3c_mctp_get_eid(struct i3c_mctp_client *client, u8 domain_id, u8 *eid) ++{ ++ /* TODO: Implement EID assignment basing on domain ID */ ++ *eid = 1; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_get_eid); ++ ++/** ++ * i3c_mctp_send_packet() - send mctp packet ++ * ++ * @tx_packet: the allocated packet that needs to be send via I3C ++ * @i3c: i3c device to send the packet to ++ * ++ * Return: 0 in case of success, a negative error code otherwise. ++ */ ++int i3c_mctp_send_packet(struct i3c_device *i3c, struct i3c_mctp_packet *tx_packet) ++{ ++ if (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && ++ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { ++ struct i3c_hdr_cmd cmds; ++ ++ cmds.mode = I3C_HDR_DDR; ++ cmds.code = 0; ++ cmds.ndatawords = DIV_ROUND_UP(tx_packet->size, 2); ++ cmds.data.out = &tx_packet->data; ++ return i3c_device_send_hdr_cmds(i3c, &cmds, 1); ++ } ++ struct i3c_priv_xfer xfers; ++ ++ xfers.rnw = false; ++ xfers.len = tx_packet->size; ++ xfers.data.out = &tx_packet->data; ++ return i3c_device_do_priv_xfers(i3c, &xfers, 1); ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_send_packet); ++ ++/** ++ * i3c_mctp_receive_packet() - receive mctp packet ++ * ++ * @client: i3c_mctp_client to receive the packet from ++ * @timeout: timeout, in jiffies ++ * ++ * The function will sleep for up to @timeout if no packet is ready to read. ++ * ++ * Returns struct i3c_mctp_packet from or ERR_PTR in case of error or the ++ * timeout elapsed. ++ */ ++struct i3c_mctp_packet *i3c_mctp_receive_packet(struct i3c_mctp_client *client, ++ unsigned long timeout) ++{ ++ struct i3c_mctp_packet *rx_packet; ++ int ret; ++ ++ ret = wait_event_interruptible_timeout(client->wait_queue, ++ __ptr_ring_peek(&client->rx_queue), timeout); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ else if (ret == 0) ++ return ERR_PTR(-ETIME); ++ ++ rx_packet = ptr_ring_consume(&client->rx_queue); ++ if (!rx_packet) ++ return ERR_PTR(-EAGAIN); ++ ++ return rx_packet; ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_receive_packet); ++ ++static void i3c_mctp_i3c_event_cb(struct i3c_device *dev, enum i3c_event event) ++{ ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(dev)); ++ ++ switch (event) { ++ case i3c_event_prepare_for_rescan: ++ /* ++ * Disable IBI and polling mode blindly. ++ */ ++ i3c_mctp_disable_ibi(dev); ++ cancel_delayed_work(&priv->polling_work); ++ break; ++ case i3c_event_rescan_done: ++ if (i3c_mctp_enable_ibi(dev)) { ++ INIT_DELAYED_WORK(&priv->polling_work, ++ i3c_mctp_polling_work); ++ schedule_delayed_work(&priv->polling_work, ++ msecs_to_jiffies(POLLING_TIMEOUT_MS)); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static int i3c_mctp_probe(struct i3c_device *i3cdev) ++{ ++ int ibi_payload_size = I3C_MCTP_IBI_PAYLOAD_SIZE; ++ struct device *dev = i3cdev_to_dev(i3cdev); ++ struct i3c_device_info info; ++ struct i3c_mctp *priv; ++ int ret; ++ ++ priv = i3c_mctp_alloc(i3cdev); ++ if (IS_ERR(priv)) ++ return PTR_ERR(priv); ++ ++ cdev_init(&priv->cdev, &i3c_mctp_fops); ++ ++ priv->cdev.owner = THIS_MODULE; ++ ret = cdev_add(&priv->cdev, MKDEV(MAJOR(i3c_mctp_devt), priv->id), 1); ++ if (ret) ++ goto error_cdev; ++ ++ /* register this i3c device with the driver core */ ++ priv->dev = device_create(i3c_mctp_class, dev, ++ MKDEV(MAJOR(i3c_mctp_devt), priv->id), ++ NULL, "i3c-mctp-%d", priv->id); ++ if (IS_ERR(priv->dev)) { ++ ret = PTR_ERR(priv->dev); ++ goto error; ++ } ++ ++ ret = i3c_device_control_pec(i3cdev, true); ++ if (ret) ++ dev_warn(priv->dev, "Hardware not support pec"); ++ ++ priv->default_client = i3c_mctp_client_alloc(priv); ++ if (IS_ERR(priv->default_client)) ++ goto error; ++ ++ dev_set_drvdata(i3cdev_to_dev(i3cdev), priv); ++ ++ priv->i3c_peci = platform_device_register_data(i3cdev_to_dev(i3cdev), "peci-i3c", priv->id, ++ NULL, 0); ++ if (IS_ERR(priv->i3c_peci)) ++ dev_warn(priv->dev, "failed to register peci-i3c device\n"); ++ ++ i3c_device_register_event_cb(i3cdev, i3c_mctp_i3c_event_cb); ++ if (i3c_mctp_enable_ibi(i3cdev)) { ++ INIT_DELAYED_WORK(&priv->polling_work, i3c_mctp_polling_work); ++ schedule_delayed_work(&priv->polling_work, msecs_to_jiffies(POLLING_TIMEOUT_MS)); ++ ibi_payload_size = 0; ++ } ++ ++ i3c_device_get_info(i3cdev, &info); ++ ++ ret = i3c_device_getmrl_ccc(i3cdev, &info); ++ if (ret || info.max_read_len != I3C_MCTP_MIN_TRANSFER_SIZE) ++ ret = i3c_device_setmrl_ccc(i3cdev, &info, I3C_MCTP_MIN_TRANSFER_SIZE, ++ ibi_payload_size); ++ if (ret && info.max_read_len != I3C_MCTP_MIN_TRANSFER_SIZE) { ++ dev_err(dev, "Failed to set MRL!, ret = %d\n", ret); ++ goto error_peci; ++ } ++ priv->max_read_len = info.max_read_len; ++ ++ ret = i3c_device_getmwl_ccc(i3cdev, &info); ++ if (ret || info.max_write_len != I3C_MCTP_MIN_TRANSFER_SIZE) ++ ret = i3c_device_setmwl_ccc(i3cdev, &info, I3C_MCTP_MIN_TRANSFER_SIZE); ++ if (ret && info.max_write_len != I3C_MCTP_MIN_TRANSFER_SIZE) { ++ dev_err(dev, "Failed to set MWL!, ret = %d\n", ret); ++ goto error_peci; ++ } ++ priv->max_write_len = info.max_write_len; ++ ++ return 0; ++ ++error_peci: ++ platform_device_unregister(priv->i3c_peci); ++ i3c_device_disable_ibi(i3cdev); ++ i3c_device_free_ibi(i3cdev); ++error: ++ cdev_del(&priv->cdev); ++error_cdev: ++ put_device(dev); ++ return ret; ++} ++ ++static void i3c_mctp_remove(struct i3c_device *i3cdev) ++{ ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); ++ ++ i3c_mctp_disable_ibi(i3cdev); ++ i3c_mctp_client_free(priv->default_client); ++ priv->default_client = NULL; ++ platform_device_unregister(priv->i3c_peci); ++ ++ device_destroy(i3c_mctp_class, MKDEV(MAJOR(i3c_mctp_devt), priv->id)); ++ cdev_del(&priv->cdev); ++ ida_free(&i3c_mctp_ida, priv->id); ++} ++ ++static const struct i3c_device_id i3c_mctp_ids[] = { ++ I3C_CLASS(0xCC, 0x0), ++ I3C_DEVICE(0x3f6, 0x8000, (void *)0), ++ I3C_DEVICE(0x3f6, 0x8001, (void *)0), ++ I3C_DEVICE(0x3f6, 0xA001, (void *)0), ++ I3C_DEVICE(0x3f6, 0xA003, (void *)0), ++ I3C_DEVICE(0x3f6, 0x0503, (void *)0), ++ { }, ++}; ++ ++static struct i3c_driver i3c_mctp_drv = { ++ .driver.name = "i3c-mctp", ++ .id_table = i3c_mctp_ids, ++ .probe = i3c_mctp_probe, ++ .remove = i3c_mctp_remove, ++}; ++ ++module_driver(i3c_mctp_drv, i3c_mctp_init, i3c_mctp_free); ++MODULE_AUTHOR("Oleksandr Shulzhenko "); ++MODULE_DESCRIPTION("I3C MCTP driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/i3c/mctp/i3c-target-mctp.c b/drivers/i3c/mctp/i3c-target-mctp.c +--- a/drivers/i3c/mctp/i3c-target-mctp.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/i3c/mctp/i3c-target-mctp.c 2026-09-09 15:51:42.670269018 +0000 +@@ -0,0 +1,489 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (C) 2022 Intel Corporation.*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define I3C_CRC8_POLYNOMIAL 0x07 ++DECLARE_CRC8_TABLE(i3c_crc8_table); ++ ++#define I3C_TARGET_MCTP_MINORS 32 ++#define RX_RING_COUNT 16 ++ ++/* ++ * IBI Mandatory Data Byte ++ * https://www.mipi.org/mipi_i3c_mandatory_data_byte_values_public ++ * ++ * MCTP: ++ * bit[7:5] = 3'b101 ++ * bit[4:0] = 5'h0E ++ */ ++#define I3C_MCTP_MDB 0xae ++ ++static struct class *i3c_target_mctp_class; ++static dev_t i3c_target_mctp_devt; ++static DEFINE_IDA(i3c_target_mctp_ida); ++ ++struct mctp_client; ++ ++struct i3c_target_mctp { ++ struct i3c_device *i3cdev; ++ struct cdev cdev; ++ int id; ++ struct mctp_client *client; ++ spinlock_t client_lock; /* to protect client access */ ++ bool mdb_append_pec; ++}; ++ ++struct mctp_client { ++ struct kref ref; ++ struct i3c_target_mctp *priv; ++ struct ptr_ring rx_queue; ++ wait_queue_head_t wait_queue; ++}; ++ ++struct mctp_packet { ++ u8 *data; ++ u16 count; ++}; ++ ++static void *i3c_target_mctp_packet_alloc(u16 count) ++{ ++ struct mctp_packet *packet; ++ u8 *data; ++ ++ packet = kzalloc(sizeof(*packet), GFP_ATOMIC); ++ if (!packet) ++ return NULL; ++ ++ data = kzalloc(count, GFP_ATOMIC); ++ if (!data) { ++ kfree(packet); ++ return NULL; ++ } ++ ++ packet->data = data; ++ packet->count = count; ++ ++ return packet; ++} ++ ++static void i3c_target_mctp_packet_free(void *data) ++{ ++ struct mctp_packet *packet = data; ++ ++ kfree(packet->data); ++ kfree(packet); ++} ++ ++static struct mctp_client *i3c_target_mctp_client_alloc(struct i3c_target_mctp *priv) ++{ ++ struct mctp_client *client; ++ ++ client = kzalloc(sizeof(*client), GFP_KERNEL); ++ if (!client) ++ goto out; ++ ++ kref_init(&client->ref); ++ client->priv = priv; ++ ptr_ring_init(&client->rx_queue, RX_RING_COUNT, GFP_KERNEL); ++out: ++ return client; ++} ++ ++static void i3c_target_mctp_client_free(struct kref *ref) ++{ ++ struct mctp_client *client = container_of(ref, typeof(*client), ref); ++ ++ ptr_ring_cleanup(&client->rx_queue, &i3c_target_mctp_packet_free); ++ ++ kfree(client); ++} ++ ++static void i3c_target_mctp_client_get(struct mctp_client *client) ++{ ++ kref_get(&client->ref); ++} ++ ++static void i3c_target_mctp_client_put(struct mctp_client *client) ++{ ++ kref_put(&client->ref, &i3c_target_mctp_client_free); ++} ++ ++static void ++i3c_target_mctp_rx_packet_enqueue(struct i3c_device *i3cdev, const u8 *data, size_t count) ++{ ++ struct i3c_target_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); ++ struct mctp_client *client; ++ struct mctp_packet *packet; ++ int ret; ++ ++ spin_lock(&priv->client_lock); ++ client = priv->client; ++ if (client) ++ i3c_target_mctp_client_get(client); ++ spin_unlock(&priv->client_lock); ++ ++ if (!client) ++ return; ++ ++ packet = i3c_target_mctp_packet_alloc(count); ++ if (!packet) ++ goto err; ++ ++ memcpy(packet->data, data, count); ++ ++ ret = ptr_ring_produce(&client->rx_queue, packet); ++ if (ret) ++ i3c_target_mctp_packet_free(packet); ++ else ++ wake_up_all(&client->wait_queue); ++err: ++ i3c_target_mctp_client_put(client); ++} ++ ++static struct mctp_client *i3c_target_mctp_create_client(struct i3c_target_mctp *priv) ++{ ++ struct mctp_client *client; ++ int ret; ++ ++ /* Currently, we support just one client. */ ++ spin_lock_irq(&priv->client_lock); ++ ret = priv->client ? -EBUSY : 0; ++ spin_unlock_irq(&priv->client_lock); ++ ++ if (ret) ++ return ERR_PTR(ret); ++ ++ client = i3c_target_mctp_client_alloc(priv); ++ if (!client) ++ return ERR_PTR(-ENOMEM); ++ ++ init_waitqueue_head(&client->wait_queue); ++ ++ spin_lock_irq(&priv->client_lock); ++ priv->client = client; ++ spin_unlock_irq(&priv->client_lock); ++ ++ return client; ++} ++ ++static void i3c_target_mctp_delete_client(struct mctp_client *client) ++{ ++ struct i3c_target_mctp *priv = client->priv; ++ ++ spin_lock_irq(&priv->client_lock); ++ priv->client = NULL; ++ spin_unlock_irq(&priv->client_lock); ++ ++ i3c_target_mctp_client_put(client); ++} ++ ++static int i3c_target_mctp_open(struct inode *inode, struct file *file) ++{ ++ struct i3c_target_mctp *priv = container_of(inode->i_cdev, struct i3c_target_mctp, cdev); ++ struct mctp_client *client; ++ ++ client = i3c_target_mctp_create_client(priv); ++ if (IS_ERR(client)) ++ return PTR_ERR(client); ++ ++ file->private_data = client; ++ ++ return 0; ++} ++ ++static int i3c_target_mctp_release(struct inode *inode, struct file *file) ++{ ++ struct mctp_client *client = file->private_data; ++ ++ i3c_target_mctp_delete_client(client); ++ ++ return 0; ++} ++ ++static ssize_t i3c_target_mctp_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct mctp_client *client = file->private_data; ++ struct mctp_packet *rx_packet; ++ ++ rx_packet = ptr_ring_consume_irq(&client->rx_queue); ++ if (!rx_packet) ++ return -EAGAIN; ++ ++ if (count < rx_packet->count) { ++ count = -EINVAL; ++ goto err_free; ++ } ++ if (count > rx_packet->count) ++ count = rx_packet->count; ++ ++ if (copy_to_user(buf, rx_packet->data, count)) ++ count = -EFAULT; ++err_free: ++ i3c_target_mctp_packet_free(rx_packet); ++ ++ return count; ++} ++ ++static u8 *pec_append(u8 addr_rnw, u8 *buf, u8 len) ++{ ++ u8 pec_v; ++ ++ pec_v = crc8(i3c_crc8_table, &addr_rnw, 1, 0); ++ pec_v = crc8(i3c_crc8_table, buf, len, pec_v); ++ buf[len] = pec_v; ++ ++ return buf; ++} ++ ++static ssize_t i3c_target_mctp_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct mctp_client *client = file->private_data; ++ struct i3c_target_mctp *priv = client->priv; ++ struct i3c_priv_xfer xfers[2] = {}; ++ struct i3c_device_info info; ++ u8 *tx_data; ++ u8 *ibi_data; ++ int ret; ++ bool ibi_enabled = i3c_device_is_ibi_enabled(priv->i3cdev); ++ ++ if (!ibi_enabled) { ++ dev_warn(i3cdev_to_dev(priv->i3cdev), "IBI not enabled\n"); ++ return count; ++ } ++ if (priv->mdb_append_pec) ++ ibi_data = kzalloc(2, GFP_KERNEL); ++ else ++ ibi_data = kzalloc(1, GFP_KERNEL); ++ if (!ibi_data) ++ return -ENOMEM; ++ ibi_data[0] = I3C_MCTP_MDB; ++ ++ tx_data = kzalloc(count, GFP_KERNEL); ++ if (!tx_data) { ++ ret = -ENOMEM; ++ goto free_ibi; ++ } ++ ++ if (copy_from_user(tx_data, buf, count)) { ++ ret = -EFAULT; ++ goto out_packet; ++ } ++ ++ i3c_device_get_info(priv->i3cdev, &info); ++ if (priv->mdb_append_pec) { ++ pec_append(info.dyn_addr << 1 | 0x1, ibi_data, 1); ++ xfers[0].len = 2; ++ } else { ++ xfers[0].len = 1; ++ } ++ xfers[0].data.out = ibi_data; ++ ++ xfers[1].data.out = tx_data; ++ xfers[1].len = count; ++ ++ ret = i3c_device_pending_read_notify(priv->i3cdev, &xfers[1], ++ &xfers[0]); ++ if (ret) ++ goto out_packet; ++ ret = count; ++ ++out_packet: ++ kfree(tx_data); ++free_ibi: ++ kfree(ibi_data); ++ return ret; ++} ++ ++static __poll_t i3c_target_mctp_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ struct mctp_client *client = file->private_data; ++ __poll_t ret = 0; ++ ++ poll_wait(file, &client->wait_queue, pt); ++ ++ if (__ptr_ring_peek(&client->rx_queue)) ++ ret |= EPOLLIN; ++ ++ /* ++ * TODO: Add support for "write" readiness. ++ * DW-I3C has a hardware queue that has finite number of entries. ++ * If we try to issue more writes that space in this queue allows for, ++ * we're in trouble. This should be handled by error from write() and ++ * poll() blocking for write events. ++ */ ++ return ret; ++} ++ ++static const struct file_operations i3c_target_mctp_fops = { ++ .owner = THIS_MODULE, ++ .open = i3c_target_mctp_open, ++ .release = i3c_target_mctp_release, ++ .read = i3c_target_mctp_read, ++ .write = i3c_target_mctp_write, ++ .poll = i3c_target_mctp_poll, ++}; ++ ++static struct i3c_target_read_setup i3c_target_mctp_rx_packet_setup = { ++ .handler = i3c_target_mctp_rx_packet_enqueue, ++}; ++ ++static ssize_t mdb_append_pec_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct i3c_device *i3cdev = dev_get_drvdata(dev); ++ struct i3c_target_mctp *priv = i3cdev_get_drvdata(i3cdev); ++ ssize_t ret; ++ ++ ret = sysfs_emit(buf, "%d\n", priv->mdb_append_pec); ++ ++ return ret; ++} ++ ++static ssize_t mdb_append_pec_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i3c_device *i3cdev = dev_get_drvdata(dev); ++ struct i3c_target_mctp *priv = i3cdev_get_drvdata(i3cdev); ++ bool res; ++ int ret; ++ ++ ret = kstrtobool(buf, &res); ++ if (ret) ++ return ret; ++ ++ priv->mdb_append_pec = res; ++ ++ return count; ++} ++ ++static DEVICE_ATTR_RW(mdb_append_pec); ++ ++static int i3c_target_mctp_probe(struct i3c_device *i3cdev) ++{ ++ struct device *parent = i3cdev_to_dev(i3cdev); ++ struct i3c_target_mctp *priv; ++ struct device *dev; ++ int ret; ++ ++ priv = devm_kzalloc(parent, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ ret = ida_alloc(&i3c_target_mctp_ida, GFP_KERNEL); ++ if (ret < 0) ++ return ret; ++ priv->id = ret; ++ ++ priv->i3cdev = i3cdev; ++ spin_lock_init(&priv->client_lock); ++ ++ cdev_init(&priv->cdev, &i3c_target_mctp_fops); ++ priv->cdev.owner = THIS_MODULE; ++ ++ ret = cdev_add(&priv->cdev, ++ MKDEV(MAJOR(i3c_target_mctp_devt), priv->id), 1); ++ if (ret) ++ goto err_ida; ++ ++ dev = device_create(i3c_target_mctp_class, parent, ++ MKDEV(MAJOR(i3c_target_mctp_devt), priv->id), i3cdev, ++ "i3c-mctp-target-%d", priv->id); ++ if (IS_ERR(dev)) { ++ ret = PTR_ERR(dev); ++ goto err_cdev; ++ } ++ ++ /* ++ * By default, the PEC is appended to the MDB as a hardware workaround for the AST2600 I3C ++ * controller as primary controller. ++ */ ++ priv->mdb_append_pec = 1; ++ ++ ret = device_create_file(dev, &dev_attr_mdb_append_pec); ++ if (unlikely(ret)) { ++ dev_err(dev, "Failed creating device attrs\n"); ++ ret = -EINVAL; ++ goto err_device; ++ } ++ ++ i3cdev_set_drvdata(i3cdev, priv); ++ ++ i3c_target_read_register(i3cdev, &i3c_target_mctp_rx_packet_setup); ++ ++ crc8_populate_msb(i3c_crc8_table, I3C_CRC8_POLYNOMIAL); ++ ++ return 0; ++ ++err_device: ++ device_destroy(i3c_target_mctp_class, ++ MKDEV(MAJOR(i3c_target_mctp_devt), priv->id)); ++err_cdev: ++ cdev_del(&priv->cdev); ++err_ida: ++ ida_free(&i3c_target_mctp_ida, priv->id); ++ ++ return ret; ++} ++ ++static void i3c_target_mctp_remove(struct i3c_device *i3cdev) ++{ ++ struct i3c_target_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); ++ ++ device_destroy(i3c_target_mctp_class, ++ MKDEV(MAJOR(i3c_target_mctp_devt), priv->id)); ++ cdev_del(&priv->cdev); ++ ida_free(&i3c_target_mctp_ida, priv->id); ++} ++ ++static const struct i3c_device_id i3c_target_mctp_ids[] = { ++ I3C_CLASS(0xcc, 0x0), ++ { }, ++}; ++ ++static struct i3c_driver i3c_target_mctp_drv = { ++ .driver.name = "i3c-target-mctp", ++ .id_table = i3c_target_mctp_ids, ++ .probe = i3c_target_mctp_probe, ++ .remove = i3c_target_mctp_remove, ++ .target = true, ++}; ++ ++static int i3c_target_mctp_init(struct i3c_driver *drv) ++{ ++ int ret; ++ ++ ret = alloc_chrdev_region(&i3c_target_mctp_devt, 0, ++ I3C_TARGET_MCTP_MINORS, "i3c-target-mctp"); ++ if (ret) ++ return ret; ++ ++ i3c_target_mctp_class = class_create("i3c-target-mctp"); ++ if (IS_ERR(i3c_target_mctp_class)) { ++ unregister_chrdev_region(i3c_target_mctp_devt, I3C_TARGET_MCTP_MINORS); ++ return PTR_ERR(i3c_target_mctp_class); ++ } ++ ++ return i3c_driver_register(drv); ++} ++ ++static void i3c_target_mctp_fini(struct i3c_driver *drv) ++{ ++ i3c_driver_unregister(drv); ++ class_destroy(i3c_target_mctp_class); ++ unregister_chrdev_region(i3c_target_mctp_devt, I3C_TARGET_MCTP_MINORS); ++} ++ ++module_driver(i3c_target_mctp_drv, i3c_target_mctp_init, i3c_target_mctp_fini); ++MODULE_AUTHOR("Iwona Winiarska "); ++MODULE_DESCRIPTION("I3C Target MCTP driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig +--- a/drivers/jtag/Kconfig 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/jtag/Kconfig 2026-09-09 15:51:40.136307308 +0000 +@@ -0,0 +1,31 @@ ++menuconfig JTAG ++ tristate "JTAG support" ++ help ++ This provides basic core functionality support for JTAG class devices. ++ Hardware that is equipped with a JTAG microcontroller can be ++ supported by using this driver's interfaces. ++ This driver exposes a set of IOCTLs to the user space for ++ the following commands: ++ SDR: Performs an IEEE 1149.1 Data Register scan ++ SIR: Performs an IEEE 1149.1 Instruction Register scan. ++ RUNTEST: Forces the IEEE 1149.1 bus to a run state for a specified ++ number of clocks or a specified time period. ++ ++ If you want this support, you should say Y here. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called jtag. ++ ++menuconfig JTAG_ASPEED ++ tristate "Aspeed SoC JTAG controller support" ++ depends on JTAG && HAS_IOMEM ++ depends on ARCH_ASPEED || COMPILE_TEST ++ help ++ This provides a support for Aspeed JTAG device, equipped on ++ Aspeed SoC 24xx and 25xx families. Drivers allows programming ++ of hardware devices, connected to SoC through the JTAG interface. ++ ++ If you want this support, you should say Y here. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called jtag-aspeed. +diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile +--- a/drivers/jtag/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/jtag/Makefile 2026-09-09 15:51:40.136307308 +0000 +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_JTAG) += jtag.o ++obj-$(CONFIG_JTAG_ASPEED) += jtag-aspeed.o +diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c +--- a/drivers/jtag/jtag.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/jtag/jtag.c 2026-09-09 15:51:40.137307293 +0000 +@@ -0,0 +1,387 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Copyright (c) 2018 Mellanox Technologies. All rights reserved. ++// Copyright (c) 2018 Oleksandr Shamray ++// Copyright (c) 2019 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *end_status_str[] = { "tlr", "idle", "selDR", "capDR", "sDR", ++ "ex1DR", "pDR", "ex2DR", "updDR", "selIR", ++ "capIR", "sIR", "ex1IR", "pIR", "ex2IR", ++ "updIR", "current" }; ++ ++struct jtag { ++ struct miscdevice miscdev; ++ const struct jtag_ops *ops; ++ int id; ++ unsigned long *priv; ++}; ++ ++static DEFINE_IDA(jtag_ida); ++ ++void *jtag_priv(struct jtag *jtag) ++{ ++ return jtag->priv; ++} ++EXPORT_SYMBOL_GPL(jtag_priv); ++ ++static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct jtag *jtag = file->private_data; ++ struct jtag_tap_state tapstate; ++ struct jtag_xfer xfer; ++ struct bitbang_packet bitbang; ++ struct tck_bitbang *bitbang_data; ++ struct jtag_mode mode; ++ u8 *xfer_data; ++ u32 data_size; ++ u32 value; ++ u32 active; ++ int err; ++ ++ if (!arg) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case JTAG_GIOCFREQ: ++ if (!jtag->ops->freq_get) ++ return -EOPNOTSUPP; ++ ++ err = jtag->ops->freq_get(jtag, &value); ++ if (err) ++ break; ++ dev_dbg(jtag->miscdev.parent, "JTAG_GIOCFREQ: freq get = %d", ++ value); ++ ++ if (put_user(value, (__u32 __user *)arg)) ++ err = -EFAULT; ++ break; ++ ++ case JTAG_SIOCFREQ: ++ if (!jtag->ops->freq_set) ++ return -EOPNOTSUPP; ++ ++ if (get_user(value, (__u32 __user *)arg)) ++ return -EFAULT; ++ if (value == 0) ++ return -EINVAL; ++ ++ err = jtag->ops->freq_set(jtag, value); ++ dev_dbg(jtag->miscdev.parent, "JTAG_SIOCFREQ: freq set = %d", ++ value); ++ break; ++ ++ case JTAG_SIOCSTATE: ++ if (copy_from_user(&tapstate, (const void __user *)arg, ++ sizeof(struct jtag_tap_state))) ++ return -EFAULT; ++ ++ if (tapstate.from > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (tapstate.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (tapstate.reset > JTAG_FORCE_RESET) ++ return -EINVAL; ++ ++ dev_dbg(jtag->miscdev.parent, ++ "JTAG_SIOCSTATE: status set from %s to %s reset %d tck %d", ++ end_status_str[tapstate.from], ++ end_status_str[tapstate.endstate], tapstate.reset, ++ tapstate.tck); ++ ++ err = jtag->ops->status_set(jtag, &tapstate); ++ break; ++ ++ case JTAG_IOCXFER: ++ { ++ u8 ubit_mask = GENMASK(7, 0); ++ u8 remaining_bits = 0x0; ++ union pad_config padding; ++ ++ if (copy_from_user(&xfer, (const void __user *)arg, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ ++ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; ++ ++ if (xfer.type > JTAG_SDR_XFER) ++ return -EINVAL; ++ ++ if (xfer.direction > JTAG_READ_WRITE_XFER) ++ return -EINVAL; ++ ++ if (xfer.from > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (xfer.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); ++ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); ++ ++ /* Save unused remaining bits in this transfer */ ++ if ((xfer.length % BITS_PER_BYTE)) { ++ ubit_mask = GENMASK((xfer.length % BITS_PER_BYTE) - 1, ++ 0); ++ remaining_bits = xfer_data[data_size - 1] & ~ubit_mask; ++ } ++ ++ if (IS_ERR(xfer_data)) ++ return -EFAULT; ++ padding.int_value = xfer.padding; ++ dev_dbg(jtag->miscdev.parent, ++ "JTAG_IOCXFER: type: %s direction: %d, END : %s, padding: (value: %d) pre_pad: %d post_pad: %d, len: %d\n", ++ xfer.type ? "DR" : "IR", xfer.direction, ++ end_status_str[xfer.endstate], padding.pad_data, ++ padding.pre_pad_number, padding.post_pad_number, ++ xfer.length); ++ ++ print_hex_dump_debug("I:", DUMP_PREFIX_NONE, 16, 1, xfer_data, ++ data_size, false); ++ ++ err = jtag->ops->xfer(jtag, &xfer, xfer_data); ++ if (err) { ++ kfree(xfer_data); ++ return err; ++ } ++ ++ print_hex_dump_debug("O:", DUMP_PREFIX_NONE, 16, 1, xfer_data, ++ data_size, false); ++ ++ /* Restore unused remaining bits in this transfer */ ++ xfer_data[data_size - 1] = (xfer_data[data_size - 1] ++ & ubit_mask) | remaining_bits; ++ ++ err = copy_to_user(u64_to_user_ptr(xfer.tdio), ++ (void *)xfer_data, data_size); ++ kfree(xfer_data); ++ if (err) ++ return -EFAULT; ++ ++ if (copy_to_user((void __user *)arg, (void *)&xfer, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ break; ++ } ++ ++ case JTAG_GIOCSTATUS: ++ err = jtag->ops->status_get(jtag, &value); ++ if (err) ++ break; ++ dev_dbg(jtag->miscdev.parent, "JTAG_GIOCSTATUS: status get %s", ++ end_status_str[value]); ++ ++ err = put_user(value, (__u32 __user *)arg); ++ break; ++ case JTAG_IOCBITBANG: ++ if (copy_from_user(&bitbang, (const void __user *)arg, ++ sizeof(struct bitbang_packet))) ++ return -EFAULT; ++ ++ if (bitbang.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; ++ ++ data_size = bitbang.length * sizeof(struct tck_bitbang); ++ bitbang_data = memdup_user((void __user *)bitbang.data, ++ data_size); ++ if (IS_ERR(bitbang_data)) ++ return -EFAULT; ++ ++ err = jtag->ops->bitbang(jtag, &bitbang, bitbang_data); ++ if (err) { ++ kfree(bitbang_data); ++ return err; ++ } ++ err = copy_to_user((void __user *)bitbang.data, ++ (void *)bitbang_data, data_size); ++ kfree(bitbang_data); ++ if (err) ++ return -EFAULT; ++ break; ++ case JTAG_SIOCMODE: ++ if (!jtag->ops->mode_set) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&mode, (const void __user *)arg, ++ sizeof(struct jtag_mode))) ++ return -EFAULT; ++ ++ dev_dbg(jtag->miscdev.parent, ++ "JTAG_SIOCMODE: mode set feature %d mode %d", ++ mode.feature, mode.mode); ++ err = jtag->ops->mode_set(jtag, &mode); ++ break; ++ case JTAG_SIOCTRST: ++ if (!jtag->ops->trst_set) ++ return -EOPNOTSUPP; ++ ++ if (get_user(active, (__u32 __user *)arg)) ++ return -EFAULT; ++ ++ dev_dbg(jtag->miscdev.parent, ++ "JTAG_SIOCTRST: active %d", active); ++ ++ err = jtag->ops->trst_set(jtag, active); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ return err; ++} ++ ++static int jtag_open(struct inode *inode, struct file *file) ++{ ++ struct jtag *jtag = container_of(file->private_data, ++ struct jtag, ++ miscdev); ++ ++ file->private_data = jtag; ++ if (jtag->ops->enable(jtag)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++static int jtag_release(struct inode *inode, struct file *file) ++{ ++ struct jtag *jtag = file->private_data; ++ ++ if (jtag->ops->disable(jtag)) ++ return -EBUSY; ++ return 0; ++} ++ ++static const struct file_operations jtag_fops = { ++ .owner = THIS_MODULE, ++ .open = jtag_open, ++ .llseek = noop_llseek, ++ .unlocked_ioctl = jtag_ioctl, ++ .release = jtag_release, ++}; ++ ++struct jtag *jtag_alloc(struct device *host, size_t priv_size, ++ const struct jtag_ops *ops) ++{ ++ struct jtag *jtag; ++ ++ if (!host) ++ return NULL; ++ ++ if (!ops) ++ return NULL; ++ ++ if (!ops->status_set || !ops->status_get || !ops->xfer) ++ return NULL; ++ ++ jtag = kzalloc(sizeof(*jtag), GFP_KERNEL); ++ if (!jtag) ++ return NULL; ++ jtag->priv = kzalloc(priv_size, GFP_KERNEL); ++ if (!jtag->priv) ++ return NULL; ++ ++ jtag->ops = ops; ++ jtag->miscdev.parent = host; ++ ++ return jtag; ++} ++EXPORT_SYMBOL_GPL(jtag_alloc); ++ ++void jtag_free(struct jtag *jtag) ++{ ++ kfree(jtag); ++} ++EXPORT_SYMBOL_GPL(jtag_free); ++ ++static int jtag_register(struct jtag *jtag) ++{ ++ struct device *dev = jtag->miscdev.parent; ++ int err; ++ int id; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); ++ if (id < 0) ++ return id; ++ ++ jtag->id = id; ++ ++ jtag->miscdev.fops = &jtag_fops; ++ jtag->miscdev.minor = MISC_DYNAMIC_MINOR; ++ jtag->miscdev.name = kasprintf(GFP_KERNEL, "jtag%d", id); ++ if (!jtag->miscdev.name) { ++ err = -ENOMEM; ++ goto err_jtag_alloc; ++ } ++ ++ err = misc_register(&jtag->miscdev); ++ if (err) { ++ dev_err(jtag->miscdev.parent, "Unable to register device\n"); ++ goto err_jtag_name; ++ } ++ return 0; ++ ++err_jtag_name: ++ kfree(jtag->miscdev.name); ++err_jtag_alloc: ++ ida_simple_remove(&jtag_ida, id); ++ return err; ++} ++ ++static void jtag_unregister(struct jtag *jtag) ++{ ++ misc_deregister(&jtag->miscdev); ++ kfree(jtag->miscdev.name); ++ ida_simple_remove(&jtag_ida, jtag->id); ++} ++ ++static void devm_jtag_unregister(struct device *dev, void *res) ++{ ++ jtag_unregister(*(struct jtag **)res); ++} ++ ++int devm_jtag_register(struct device *dev, struct jtag *jtag) ++{ ++ struct jtag **ptr; ++ int ret; ++ ++ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *), ++ GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; ++ ++ ret = jtag_register(jtag); ++ if (!ret) { ++ *ptr = jtag; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(devm_jtag_register); ++ ++static void __exit jtag_exit(void) ++{ ++ ida_destroy(&jtag_ida); ++} ++ ++module_exit(jtag_exit); ++ ++MODULE_AUTHOR("Oleksandr Shamray "); ++MODULE_DESCRIPTION("Generic jtag support"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/net/mctp/mctp-pcie-vdm.c b/drivers/net/mctp/mctp-pcie-vdm.c +--- a/drivers/net/mctp/mctp-pcie-vdm.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/drivers/net/mctp/mctp-pcie-vdm.c 2026-09-09 15:51:45.736222689 +0000 +@@ -0,0 +1,373 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * mctp-pcie-vdm.c - MCTP-over-PCIe-VDM (DMTF DSP0238) transport binding driver. ++ * ++ * DSP0238 is available at: ++ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0238_1.2.0.pdf ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// 64bytes mctp payload + 4bytes mctp header ++#define MCTP_PCIE_VDM_MIN_MTU (64 + 4) ++#define MCTP_PCIE_VDM_MAX_MTU 512 ++/* 16byte */ ++#define MCTP_PCIE_VDM_HDR_SIZE 16 ++#define MCTP_PAYLOAD_IC_TYPE_SIZE 1 ++#define MCTP_RECEIVE_PKT_TIMEOUT_MS 5 ++ ++#define MCTP_PCIE_VDM_NET_DEV_TX_QUEUE_LEN 1100 ++#define MCTP_PCIE_VDM_DEV_TX_QUEUE_SIZE 64 ++ ++#define MCTP_PCIE_VDM_FMT_4DW 0x3 ++#define MCTP_PCIE_VDM_TYPE_MSG 0x10 ++#define MCTP_PCIE_VDM_CODE 0x0 ++/* PCIe VDM message code */ ++#define MCTP_PCIE_VDM_MSG_CODE 0x7F ++#define MCTP_PCIE_VDM_VENDOR_ID 0x1AB4 ++/* MCTP message type */ ++#define MCTP_MSG_TYPE_MASK GENMASK(6, 0) ++#define MCTP_PCIE_VDM_MSG_TYPE 0x7E ++ ++#define MCTP_PCIE_SWAP_NET_ENDIAN(arr, len) \ ++ do { \ ++ u32 *p = (u32 *)(arr); \ ++ for (int i = 0; i < (len); i++) { \ ++ p[i] = htonl(p[i]); \ ++ } \ ++ } while (0) ++ ++#define MCTP_PCIE_SWAP_LITTLE_ENDIAN(arr, len) \ ++ do { \ ++ u32 *p = (u32 *)(arr); \ ++ for (int i = 0; i < (len); i++) { \ ++ p[i] = ntohl(p[i]); \ ++ p[i] = cpu_to_le32(p[i]); \ ++ } \ ++ } while (0) ++ ++enum mctp_pcie_vdm_route_type { ++ MCTP_PCIE_VDM_ROUTE_TO_RC = 0, ++ MCTP_PCIE_VDM_ROUTE_BY_ID = 2, ++ MCTP_PCIE_VDM_BROADCAST_FROM_RC = 3, ++}; ++ ++struct mctp_pcie_vdm_hdr { ++ u32 length : 10, rsvd0 : 2, attr : 2, ep : 1, td : 1, rsvd1 : 4, tc : 3, ++ rsvd2 : 1, route_type : 5, fmt : 2, rsvd3 : 1; ++ u8 msg_code; ++ u8 tag_vdm_code : 4, tag_pad_len : 2, tag_rsvd : 2; ++ u16 pci_req_id; ++ u16 pci_vendor_id; ++ u16 pci_target_id; ++}; ++ ++struct mctp_pcie_vdm_dev { ++ struct device *dev; ++ const struct mctp_pcie_vdm_ops *callback_ops; ++}; ++ ++static const struct mctp_pcie_vdm_hdr mctp_pcie_vdm_hdr_template = { ++ .fmt = MCTP_PCIE_VDM_FMT_4DW, ++ .route_type = MCTP_PCIE_VDM_TYPE_MSG | MCTP_PCIE_VDM_ROUTE_BY_ID, ++ .tag_vdm_code = MCTP_PCIE_VDM_CODE, ++ .msg_code = MCTP_PCIE_VDM_MSG_CODE, ++ .pci_vendor_id = MCTP_PCIE_VDM_VENDOR_ID, ++ .attr = 0, ++}; ++ ++static void mctp_pcie_vdm_display_skb_buff_data(struct sk_buff *skb) ++{ ++ int i = 0; ++ ++ while ((i + 4) < skb->len) { ++ pr_debug("%02x %02x %02x %02x\n", skb->data[i], ++ skb->data[i + 1], skb->data[i + 2], skb->data[i + 3]); ++ i += 4; ++ } ++ ++ char buf[16] = { 0 }; ++ char *p = buf; ++ ++ while (i < skb->len) { ++ p += snprintf(p, sizeof(buf) - (p - buf), "%02x ", ++ skb->data[i]); ++ i++; ++ } ++ pr_debug("%s\n", buf); ++} ++ ++static int mctp_pcie_vdm_xmit(struct net_device *ndev, struct sk_buff *skb) ++{ ++ struct net_device_stats *stats; ++ struct mctp_pcie_vdm_hdr *hdr; ++ struct mctp_pcie_vdm_dev *vdm_dev; ++ u8 *hdr_byte; ++ u16 payload_len_dw; ++ u16 payload_len_byte; ++ int rc; ++ ++ stats = &ndev->stats; ++ vdm_dev = netdev_priv(ndev); ++ hdr = (struct mctp_pcie_vdm_hdr *)skb->data; ++ hdr_byte = skb->data; ++ payload_len_dw = (ALIGN(skb->len, sizeof(u32)) - MCTP_PCIE_VDM_HDR_SIZE) / sizeof(u32); ++ payload_len_byte = skb->len - MCTP_PCIE_VDM_HDR_SIZE; ++ ++ hdr->length = payload_len_dw; ++ hdr->tag_pad_len = ++ ALIGN(payload_len_byte, sizeof(u32)) - payload_len_byte; ++ pr_debug("%s: skb len %d pad len %d\n", __func__, skb->len, ++ hdr->tag_pad_len); ++ MCTP_PCIE_SWAP_NET_ENDIAN((u32 *)hdr, ++ sizeof(struct mctp_pcie_vdm_hdr) / sizeof(u32)); ++ ++ mctp_pcie_vdm_display_skb_buff_data(skb); ++ rc = vdm_dev->callback_ops->send_packet(vdm_dev->dev, skb->data, payload_len_dw * sizeof(u32)); ++ ++ if (rc) { ++ pr_err("%s: failed to send packet, rc %d\n", __func__, rc); ++ stats->tx_errors++; ++ if (rc != -ENOSPC && rc != -EBUSY) ++ stats->tx_dropped++; ++ } else { ++ stats->tx_packets++; ++ stats->tx_bytes += (skb->len - sizeof(struct mctp_pcie_vdm_hdr)); ++ } ++ return rc; ++} ++ ++static netdev_tx_t mctp_pcie_vdm_start_xmit(struct sk_buff *skb, ++ struct net_device *ndev) ++{ ++ int rc; ++ netdev_tx_t ret; ++ ++ pr_debug("%s: skb len %u\n", __func__, skb->len); ++ ++ if (skb) { ++ rc = mctp_pcie_vdm_xmit(ndev, skb); ++ if (rc) { ++ pr_err("%s: failed to send packet, rc %d\n", __func__, rc); ++ if (rc == -ENOSPC || rc == -EBUSY) { ++ ret = NETDEV_TX_BUSY; ++ return ret; ++ } ++ } ++ ret = NETDEV_TX_OK; ++ kfree_skb(skb); ++ } ++ return ret; ++} ++ ++static void mctp_pcie_vdm_uninit(struct net_device *ndev) ++{ ++ struct mctp_pcie_vdm_dev *vdm_dev; ++ ++ vdm_dev = netdev_priv(ndev); ++ pr_info("%s: uninitializing vdm_dev %s\n", __func__, ++ ndev->name); ++ vdm_dev->callback_ops->uninit(vdm_dev->dev); ++} ++ ++static int mctp_pcie_vdm_hdr_create(struct sk_buff *skb, ++ struct net_device *ndev, ++ unsigned short type, const void *daddr, ++ const void *saddr, unsigned int len) ++{ ++ u8 dest_addr[3] = {0}; ++ struct mctp_pcie_vdm_hdr *hdr = ++ (struct mctp_pcie_vdm_hdr *)skb_push(skb, sizeof(*hdr)); ++ ++ pr_debug("%s type %d len %d\n", __func__, type, len); ++ memcpy(hdr, &mctp_pcie_vdm_hdr_template, sizeof(*hdr)); ++ if (daddr) { ++ memcpy(dest_addr, (u8 *)daddr, sizeof(dest_addr)); ++ hdr->route_type |= dest_addr[0] & GENMASK(2, 0); ++ hdr->pci_target_id = dest_addr[1] << 8 | dest_addr[2]; ++ pr_debug("%s dst route %d addr %d\n", __func__, hdr->route_type, hdr->pci_target_id); ++ } ++ ++ if (saddr) { ++ pr_debug("%s src addr %d\n", __func__, *(u16 *)saddr); ++ hdr->pci_req_id = *(u16 *)saddr; ++ } ++ ++ return 0; ++} ++ ++static const struct net_device_ops mctp_pcie_vdm_net_ops = { ++ .ndo_start_xmit = mctp_pcie_vdm_start_xmit, ++ .ndo_uninit = mctp_pcie_vdm_uninit, ++}; ++ ++static const struct header_ops mctp_pcie_vdm_net_hdr_ops = { ++ .create = mctp_pcie_vdm_hdr_create, ++}; ++ ++static void mctp_pcie_vdm_net_setup(struct net_device *ndev) ++{ ++ ndev->type = ARPHRD_MCTP; ++ ++ ndev->mtu = MCTP_PCIE_VDM_MIN_MTU; ++ ndev->min_mtu = MCTP_PCIE_VDM_MIN_MTU; ++ ndev->max_mtu = MCTP_PCIE_VDM_MAX_MTU; ++ ndev->tx_queue_len = MCTP_PCIE_VDM_NET_DEV_TX_QUEUE_LEN; ++ ndev->addr_len = 3; //PCIe bdf is 2bytes + 1byte route type ++ ndev->hard_header_len = sizeof(struct mctp_pcie_vdm_hdr); ++ ++ ndev->netdev_ops = &mctp_pcie_vdm_net_ops; ++ ndev->header_ops = &mctp_pcie_vdm_net_hdr_ops; ++} ++ ++static int mctp_pcie_vdm_add_net_dev(struct net_device **dev, const char *ifname) ++{ ++ struct net_device *ndev = alloc_netdev(sizeof(struct mctp_pcie_vdm_dev), ++ ifname ? ifname : "mctppci%d", ++ NET_NAME_UNKNOWN, ++ mctp_pcie_vdm_net_setup); ++ ++ if (!ndev) { ++ pr_err("%s: failed to allocate net device\n", __func__); ++ return -ENOMEM; ++ } ++ dev_net_set(ndev, current->nsproxy->net_ns); ++ ++ *dev = ndev; ++ int rc; ++ ++ rc = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_PCIE_VDM); ++ if (rc) { ++ pr_err("%s: failed to register net device\n", __func__); ++ free_netdev(ndev); ++ return rc; ++ } ++ return rc; ++} ++ ++void mctp_pcie_vdm_receive_packet(struct net_device *ndev) ++{ ++ struct mctp_pcie_vdm_dev *vdm_dev; ++ u8 *packet; ++ ++ vdm_dev = netdev_priv(ndev); ++ packet = vdm_dev->callback_ops->recv_packet(vdm_dev->dev); ++ ++ while (!IS_ERR(packet)) { ++ MCTP_PCIE_SWAP_LITTLE_ENDIAN((u32 *)packet, ++ sizeof(struct mctp_pcie_vdm_hdr) / sizeof(u32)); ++ struct mctp_pcie_vdm_hdr *vdm_hdr = (struct mctp_pcie_vdm_hdr *)packet; ++ struct mctp_skb_cb *cb; ++ struct net_device_stats *stats; ++ struct sk_buff *skb; ++ u16 len; ++ int net_status; ++ ++ stats = &ndev->stats; ++ len = vdm_hdr->length * sizeof(u32) - ++ vdm_hdr->tag_pad_len; ++ len += (MCTP_PCIE_VDM_HDR_SIZE - sizeof(struct mctp_pcie_vdm_hdr)); ++ skb = netdev_alloc_skb(ndev, len); ++ pr_debug("%s: received packet size: %d\n", __func__, ++ len); ++ ++ if (!skb) { ++ stats->rx_errors++; ++ pr_err("%s: failed to alloc skb\n", __func__); ++ continue; ++ } ++ ++ skb->protocol = htons(ETH_P_MCTP); ++ /* put data into tail sk buff */ ++ skb_put_data(skb, &packet[sizeof(struct mctp_pcie_vdm_hdr)], len); ++ mctp_pcie_vdm_display_skb_buff_data(skb); ++ ++ cb = __mctp_cb(skb); ++ cb->halen = 3; // route type | bdf address ++ cb->haddr[0] = vdm_hdr->route_type & GENMASK(2, 0); ++ cb->haddr[1] = vdm_hdr->pci_req_id >> 8; ++ cb->haddr[2] = vdm_hdr->pci_req_id & 0xFF; ++ net_status = netif_rx(skb); ++ if (net_status == NET_RX_SUCCESS) { ++ stats->rx_packets++; ++ stats->rx_bytes += len; ++ } else { ++ stats->rx_dropped++; ++ } ++ ++ vdm_dev->callback_ops->free_packet(packet); ++ packet = vdm_dev->callback_ops->recv_packet(vdm_dev->dev); ++ } ++} ++ ++struct net_device *mctp_pcie_vdm_add_dev(struct device *dev, ++ const struct mctp_pcie_vdm_ops *ops, ++ const char *ifname) ++{ ++ struct net_device *ndev; ++ struct mctp_pcie_vdm_dev *vdm_dev; ++ int rc; ++ ++ rc = mctp_pcie_vdm_add_net_dev(&ndev, ifname); ++ if (rc) { ++ pr_err("%s: failed to add net device\n", __func__); ++ return ERR_PTR(rc); ++ } ++ ++ vdm_dev = netdev_priv(ndev); ++ vdm_dev->dev = dev; ++ vdm_dev->callback_ops = ops; ++ ++ return ndev; ++} ++EXPORT_SYMBOL_GPL(mctp_pcie_vdm_add_dev); ++ ++void mctp_pcie_vdm_remove_dev(struct net_device *vdm_dev) ++{ ++ pr_debug("%s: removing vdm_dev %s\n", __func__, vdm_dev->name); ++ ++ if (vdm_dev) { ++ mctp_unregister_netdev(vdm_dev); ++ free_netdev(vdm_dev); ++ } ++} ++EXPORT_SYMBOL_GPL(mctp_pcie_vdm_remove_dev); ++ ++void mctp_pcie_vdm_set_carrier(struct net_device *ndev, bool up) ++{ ++ if (!ndev) { ++ pr_err("%s: ndev is NULL\n", __func__); ++ return; ++ } ++ ++ if (up) ++ netif_carrier_on(ndev); ++ else ++ netif_carrier_off(ndev); ++} ++EXPORT_SYMBOL_GPL(mctp_pcie_vdm_set_carrier); +diff --git a/include/linux/mctp-pcie-vdm.h b/include/linux/mctp-pcie-vdm.h +--- a/include/linux/mctp-pcie-vdm.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/include/linux/mctp-pcie-vdm.h 2026-09-09 15:51:45.727222825 +0000 +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * mctp-pcie-vdm.h - MCTP-over-PCIe-VDM (DMTF DSP0238) transport binding Interface ++ * for PCIe VDM devices to register and implement. ++ * ++ */ ++ ++#ifndef __LINUX_MCTP_PCIE_VDM_H ++#define __LINUX_MCTP_PCIE_VDM_H ++ ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_MCTP_TRANSPORT_PCIE_VDM) ++ ++/** ++ * @send_packet: referenced to send packets with PCIe VDM header packed. ++ * @recv_packet: referenced multiple times until no RX packet to be handled. ++ * received pointer shall start from the PCIe VDM header. ++ * @free_packet: referenced when the packet is processed and okay to be freed. ++ * @uninit: uninitialize the device. ++ */ ++struct mctp_pcie_vdm_ops { ++ int (*send_packet)(struct device *dev, u8 *data, size_t len); ++ u8 *(*recv_packet)(struct device *dev); ++ void (*free_packet)(void *packet); ++ void (*uninit)(struct device *dev); ++}; ++ ++struct net_device *mctp_pcie_vdm_add_dev(struct device *dev, ++ const struct mctp_pcie_vdm_ops *ops, ++ const char *ifname); ++void mctp_pcie_vdm_receive_packet(struct net_device *ndev); ++void mctp_pcie_vdm_remove_dev(struct net_device *ndev); ++void mctp_pcie_vdm_set_carrier(struct net_device *ndev, bool up); ++ ++#endif /* CONFIG_MCTP_TRANSPORT_PCIE_VDM */ ++#endif /* __LINUX_MCTP_PCIE_VDM_H */ +diff --git a/include/trace/events/xdma.h b/include/trace/events/xdma.h +--- a/include/trace/events/xdma.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/include/trace/events/xdma.h 2026-09-09 15:51:45.744222568 +0000 +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM xdma ++ ++#if !defined(_TRACE_XDMA_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _TRACE_XDMA_H ++ ++#include ++ ++TRACE_EVENT(xdma_start, ++ TP_PROTO(const struct aspeed_xdma *ctx, const struct aspeed_xdma_cmd *cmd), ++ TP_ARGS(ctx, cmd), ++ TP_STRUCT__entry(__field(bool, dir_upstream) ++ __field(unsigned int, index) ++ __field(__u64, host) ++ __field(__u64, pitch) ++ __field(__u64, cmd) ++ ), ++ TP_fast_assign(__entry->dir_upstream = ctx->upstream; ++ __entry->index = ctx->cmd_idx; ++ __entry->host = cmd->host_addr; ++ __entry->pitch = cmd->pitch; ++ __entry->cmd = cmd->cmd; ++ ), ++ TP_printk("%s cmd:%u [%08llx %016llx %016llx]", ++ __entry->dir_upstream ? "upstream" : "downstream", ++ __entry->index, ++ __entry->host, ++ __entry->pitch, ++ __entry->cmd ++ ) ++); ++ ++TRACE_EVENT(xdma_irq, ++ TP_PROTO(u32 sts), ++ TP_ARGS(sts), ++ TP_STRUCT__entry(__field(__u32, status) ++ ), ++ TP_fast_assign(__entry->status = sts; ++ ), ++ TP_printk("sts:%08x", ++ __entry->status ++ ) ++); ++ ++TRACE_EVENT(xdma_reset, ++ TP_PROTO(const struct aspeed_xdma *ctx), ++ TP_ARGS(ctx), ++ TP_STRUCT__entry(__field(bool, dir_upstream) ++ __field(bool, in_progress) ++ ), ++ TP_fast_assign(__entry->dir_upstream = ctx->upstream; ++ __entry->in_progress = ++ ctx->current_client ? ctx->current_client->in_progress : false; ++ ), ++ TP_printk("%sin progress%s", ++ __entry->in_progress ? "" : "not ", ++ __entry->in_progress ? (__entry->dir_upstream ? ++ " upstream" : " downstream") : "" ++ ) ++); ++ ++TRACE_EVENT(xdma_perst, ++ TP_PROTO(const struct aspeed_xdma *ctx), ++ TP_ARGS(ctx), ++ TP_STRUCT__entry(__field(bool, in_reset) ++ ), ++ TP_fast_assign(__entry->in_reset = ctx->in_reset; ++ ), ++ TP_printk("%s", ++ __entry->in_reset ? "in reset" : "" ++ ) ++); ++ ++TRACE_EVENT(xdma_unmap, ++ TP_PROTO(const struct aspeed_xdma_client *client), ++ TP_ARGS(client), ++ TP_STRUCT__entry(__field(__u32, phys) ++ __field(__u32, size) ++ ), ++ TP_fast_assign(__entry->phys = client->phys; ++ __entry->size = client->size; ++ ), ++ TP_printk("p:%08x s:%08x", ++ __entry->phys, ++ __entry->size ++ ) ++); ++ ++TRACE_EVENT(xdma_mmap_error, ++ TP_PROTO(const struct aspeed_xdma_client *client, unsigned long vm_start), ++ TP_ARGS(client, vm_start), ++ TP_STRUCT__entry(__field(__u32, phys) ++ __field(__u32, size) ++ __field(unsigned long, vm_start) ++ ), ++ TP_fast_assign(__entry->phys = client->phys; ++ __entry->size = client->size; ++ __entry->vm_start = vm_start; ++ ), ++ TP_printk("p:%08x s:%08x v:%08lx", ++ __entry->phys, ++ __entry->size, ++ __entry->vm_start ++ ) ++); ++ ++TRACE_EVENT(xdma_mmap, ++ TP_PROTO(const struct aspeed_xdma_client *client), ++ TP_ARGS(client), ++ TP_STRUCT__entry(__field(__u32, phys) ++ __field(__u32, size) ++ ), ++ TP_fast_assign(__entry->phys = client->phys; ++ __entry->size = client->size; ++ ), ++ TP_printk("p:%08x s:%08x", ++ __entry->phys, ++ __entry->size ++ ) ++); ++ ++#endif /* _TRACE_XDMA_H */ ++ ++#include diff --git a/patches-sonic/0002-net-bridge-vxlan-Protocol-field-in-bridge-fdb.patch b/patches-sonic/0002-net-bridge-vxlan-Protocol-field-in-bridge-fdb.patch index 22bfe9744..f49434b8c 100644 --- a/patches-sonic/0002-net-bridge-vxlan-Protocol-field-in-bridge-fdb.patch +++ b/patches-sonic/0002-net-bridge-vxlan-Protocol-field-in-bridge-fdb.patch @@ -217,7 +217,7 @@ index ffb0b61..7e08ae3 100644 hash_index = fdb_head_index(vxlan, addr, src_vni); spin_lock_bh(&vxlan->hash_lock[hash_index]); + if (protocol != RTPROT_UNSPEC) { -+ f = vxlan_find_mac(vxlan, addr, src_vni); ++ f = vxlan_find_mac_tx(vxlan, addr, src_vni); + if (!f || f->protocol != protocol) { + err = -ENOENT; + goto out; diff --git a/patches-sonic/0003-arm64-dts-marvell-Add-NAND-flash-controller-to-AC5.patch b/patches-sonic/0003-arm64-dts-marvell-Add-NAND-flash-controller-to-AC5.patch deleted file mode 100644 index b19946b94..000000000 --- a/patches-sonic/0003-arm64-dts-marvell-Add-NAND-flash-controller-to-AC5.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 58fe732052196777112fdba536fb9db5cdd42ec6 Mon Sep 17 00:00:00 2001 -From: Chris Packham -Date: Mon, 3 Jul 2023 15:50:43 +1200 -Subject: arm64: dts: marvell: Add NAND flash controller to AC5 - -The AC5/AC5X SoC has a NAND flash controller (NFC). Add this to -the base SoC dtsi file as a disabled node. The NFC integration -on the AC5/AC5X only supports SDR timing modes up to 3 so requires a -dedicated compatible property so this limitation can be enforced. - -Signed-off-by: Chris Packham -Signed-off-by: Gregory CLEMENT ---- - arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -index 67c4688546b8..62d03ffa9485 100644 ---- a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -+++ b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -@@ -297,6 +297,16 @@ spi1: spi@805a8000 { - status = "disabled"; - }; - -+ nand: nand-controller@805b0000 { -+ compatible = "marvell,ac5-nand-controller"; -+ reg = <0x0 0x805b0000 0x0 0x00000054>; -+ #address-cells = <0x1>; -+ #size-cells = <0x0>; -+ interrupts = ; -+ clocks = <&nand_clock>; -+ status = "disabled"; -+ }; -+ - gic: interrupt-controller@80600000 { - compatible = "arm,gic-v3"; - #interrupt-cells = <3>; -@@ -319,5 +329,11 @@ spi_clock: spi-clock { - #clock-cells = <0>; - clock-frequency = <200000000>; - }; -+ -+ nand_clock: nand-clock { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <400000000>; -+ }; - }; - }; --- -2.25.1 - diff --git a/patches-sonic/0003-aspeed-ast2700-aspeed-diff-vendor-independent-changes-update-to-6.12-00.07.02.patch b/patches-sonic/0003-aspeed-ast2700-aspeed-diff-vendor-independent-changes-update-to-6.12-00.07.02.patch deleted file mode 100644 index 82bf251c0..000000000 --- a/patches-sonic/0003-aspeed-ast2700-aspeed-diff-vendor-independent-changes-update-to-6.12-00.07.02.patch +++ /dev/null @@ -1,1963 +0,0 @@ -From 8f00d7f476aec432ee298f7c94c90b9035766a04 Mon Sep 17 00:00:00 2001 -From: Chander -Date: Wed, 13 May 2026 23:09:41 +0000 -Subject: [PATCH] Vendor independent changes - -This patch adds support for Aspeed AST2700 ARM64 SoC including: -- Device tree files for AST2700 and related boards -- Aspeed-specific drivers (pinctrl, clk, soc, crypto, etc.) -- Faraday ethernet driver support -- Kconfig and Makefile updates - -This patch targets vendor independent changes as part of updating to -kernel-6.12 00.07.02. - -Signed-off-by: Chander - ---- - drivers/edac/altera_edac.c | 1 - drivers/edac/edac_mc_sysfs.c | 24 - - drivers/edac/i10nm_base.c | 14 - drivers/gpio/gpio-aspeed-sgpio.c | 749 +++++++++----------------- - drivers/i3c/master/ast2600-i3c-master.c | 34 + - drivers/irqchip/Kconfig | 3 - drivers/media/platform/aspeed/aspeed-video.c | 48 +- - drivers/net/ethernet/faraday/ftgmac100.c | 384 +++++++++++++ - drivers/net/ethernet/faraday/ftgmac100.h | 39 + - drivers/net/mctp/mctp-pcie-vdm.c | 12 - drivers/rtc/rtc-aspeed.c | 22 - - drivers/usb/gadget/udc/aspeed-vhub/core.c | 6 - drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 4 - 13 files changed, 772 insertions(+), 568 deletions(-) - -diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c -index 605493b50..a059964b9 100644 ---- a/drivers/edac/altera_edac.c -+++ b/drivers/edac/altera_edac.c -@@ -128,6 +128,7 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file, - - ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL); - if (!ptemp) { -+ dma_free_coherent(mci->pdev, 16, ptemp, dma_handle); - edac_printk(KERN_ERR, EDAC_MC, - "Inject: Buffer Allocation error\n"); - return -ENOMEM; -diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c -index 70dc0ee1c..4200aec04 100644 ---- a/drivers/edac/edac_mc_sysfs.c -+++ b/drivers/edac/edac_mc_sysfs.c -@@ -305,14 +305,6 @@ DEVICE_CHANNEL(ch10_dimm_label, S_IRUGO | S_IWUSR, - channel_dimm_label_show, channel_dimm_label_store, 10); - DEVICE_CHANNEL(ch11_dimm_label, S_IRUGO | S_IWUSR, - channel_dimm_label_show, channel_dimm_label_store, 11); --DEVICE_CHANNEL(ch12_dimm_label, S_IRUGO | S_IWUSR, -- channel_dimm_label_show, channel_dimm_label_store, 12); --DEVICE_CHANNEL(ch13_dimm_label, S_IRUGO | S_IWUSR, -- channel_dimm_label_show, channel_dimm_label_store, 13); --DEVICE_CHANNEL(ch14_dimm_label, S_IRUGO | S_IWUSR, -- channel_dimm_label_show, channel_dimm_label_store, 14); --DEVICE_CHANNEL(ch15_dimm_label, S_IRUGO | S_IWUSR, -- channel_dimm_label_show, channel_dimm_label_store, 15); - - /* Total possible dynamic DIMM Label attribute file table */ - static struct attribute *dynamic_csrow_dimm_attr[] = { -@@ -328,10 +320,6 @@ static struct attribute *dynamic_csrow_dimm_attr[] = { - &dev_attr_legacy_ch9_dimm_label.attr.attr, - &dev_attr_legacy_ch10_dimm_label.attr.attr, - &dev_attr_legacy_ch11_dimm_label.attr.attr, -- &dev_attr_legacy_ch12_dimm_label.attr.attr, -- &dev_attr_legacy_ch13_dimm_label.attr.attr, -- &dev_attr_legacy_ch14_dimm_label.attr.attr, -- &dev_attr_legacy_ch15_dimm_label.attr.attr, - NULL - }; - -@@ -360,14 +348,6 @@ DEVICE_CHANNEL(ch10_ce_count, S_IRUGO, - channel_ce_count_show, NULL, 10); - DEVICE_CHANNEL(ch11_ce_count, S_IRUGO, - channel_ce_count_show, NULL, 11); --DEVICE_CHANNEL(ch12_ce_count, S_IRUGO, -- channel_ce_count_show, NULL, 12); --DEVICE_CHANNEL(ch13_ce_count, S_IRUGO, -- channel_ce_count_show, NULL, 13); --DEVICE_CHANNEL(ch14_ce_count, S_IRUGO, -- channel_ce_count_show, NULL, 14); --DEVICE_CHANNEL(ch15_ce_count, S_IRUGO, -- channel_ce_count_show, NULL, 15); - - /* Total possible dynamic ce_count attribute file table */ - static struct attribute *dynamic_csrow_ce_count_attr[] = { -@@ -383,10 +363,6 @@ static struct attribute *dynamic_csrow_ce_count_attr[] = { - &dev_attr_legacy_ch9_ce_count.attr.attr, - &dev_attr_legacy_ch10_ce_count.attr.attr, - &dev_attr_legacy_ch11_ce_count.attr.attr, -- &dev_attr_legacy_ch12_ce_count.attr.attr, -- &dev_attr_legacy_ch13_ce_count.attr.attr, -- &dev_attr_legacy_ch14_ce_count.attr.attr, -- &dev_attr_legacy_ch15_ce_count.attr.attr, - NULL - }; - -diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c -index d8cd12d90..ac4b3d955 100644 ---- a/drivers/edac/i10nm_base.c -+++ b/drivers/edac/i10nm_base.c -@@ -967,15 +967,6 @@ static bool i10nm_check_ecc(struct skx_imc *imc, int chan) - return !!GET_BITFIELD(mcmtr, 2, 2); - } - --static bool i10nm_channel_disabled(struct skx_imc *imc, int chan) --{ -- u32 mcmtr = I10NM_GET_MCMTR(imc, chan); -- -- edac_dbg(1, "mc%d ch%d mcmtr reg %x\n", imc->mc, chan, mcmtr); -- -- return (mcmtr == ~0 || GET_BITFIELD(mcmtr, 18, 18)); --} -- - static int i10nm_get_dimm_config(struct mem_ctl_info *mci, - struct res_config *cfg) - { -@@ -989,11 +980,6 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci, - if (!imc->mbase) - continue; - -- if (i10nm_channel_disabled(imc, i)) { -- edac_dbg(1, "mc%d ch%d is disabled.\n", imc->mc, i); -- continue; -- } -- - ndimms = 0; - - if (res_cfg->type != GNR) -diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c -index 150fbaebb..836b0cc76 100644 ---- a/drivers/gpio/gpio-aspeed-sgpio.c -+++ b/drivers/gpio/gpio-aspeed-sgpio.c -@@ -6,6 +6,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -18,6 +19,10 @@ - #include - #include - -+/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -+#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) -+ - #define SGPIO_G7_IRQ_STS_BASE 0x40 - #define SGPIO_G7_IRQ_STS_OFFSET(x) (SGPIO_G7_IRQ_STS_BASE + (x) * 0x4) - #define SGPIO_G7_CTRL_REG_BASE 0x80 -@@ -39,30 +44,10 @@ - #define SGPIO_G7_PARALLEL_OUT_SEL GENMASK(19, 18) - #define SELECT_FROM_CSR 0 - #define SELECT_FROM_PARALLEL_IN 1 --#define SELECT_FROM_SERIAL_IN 1 -+#define SELECT_FROM_SERIAL_IN 2 - --#define BMC_CONTROL_START_INDEX 128 --#define BMC_CONTROL_END_INDEX 143 -- --static inline u32 field_get(u32 _mask, u32 _val) --{ -- return (((_val) & (_mask)) >> (ffs(_mask) - 1)); --} -- --static inline u32 field_prep(u32 _mask, u32 _val) --{ -- return (((_val) << (ffs(_mask) - 1)) & (_mask)); --} -- --static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) --{ -- iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); --} -- --static inline void ast_clr_bits(void __iomem *addr, u32 mask) --{ -- iowrite32((ioread32(addr) & ~(mask)), addr); --} -+#define ASPEED_SGPIO_G4_CFG_OFFSET 0x54 -+#define ASPEED_SGPIO_G7_CFG_OFFSET 0x0 - - #define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) - #define ASPEED_SGPIO_ENABLE BIT(0) -@@ -70,9 +55,8 @@ static inline void ast_clr_bits(void __iomem *addr, u32 mask) - - struct aspeed_sgpio_pdata { - const u32 pin_mask; -- const u16 ctrl_reg; -- const int version; -- const bool slave; -+ const struct aspeed_sgpio_llops *llops; -+ const u32 cfg_offset; - }; - - struct aspeed_sgpio { -@@ -82,7 +66,6 @@ struct aspeed_sgpio { - raw_spinlock_t lock; - void __iomem *base; - int irq; -- int version; - const struct aspeed_sgpio_pdata *pdata; - }; - -@@ -91,7 +74,6 @@ struct aspeed_sgpio_bank { - u16 rdata_reg; - u16 irq_regs; - u16 tolerance_regs; -- const char names[4][3]; - }; - - /* -@@ -107,28 +89,24 @@ static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { - .rdata_reg = 0x0070, - .irq_regs = 0x0004, - .tolerance_regs = 0x0018, -- .names = { "A", "B", "C", "D" }, - }, - { - .val_regs = 0x001C, - .rdata_reg = 0x0074, - .irq_regs = 0x0020, - .tolerance_regs = 0x0034, -- .names = { "E", "F", "G", "H" }, - }, - { - .val_regs = 0x0038, - .rdata_reg = 0x0078, - .irq_regs = 0x003C, - .tolerance_regs = 0x0050, -- .names = { "I", "J", "K", "L" }, - }, - { - .val_regs = 0x0090, - .rdata_reg = 0x007C, - .irq_regs = 0x0094, - .tolerance_regs = 0x00A8, -- .names = { "M", "N", "O", "P" }, - }, - }; - -@@ -143,6 +121,15 @@ enum aspeed_sgpio_reg { - reg_tolerance, - }; - -+struct aspeed_sgpio_llops { -+ void (*reg_bit_set)(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg, bool val); -+ bool (*reg_bit_get)(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg); -+ int (*reg_bank_get)(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg); -+}; -+ - #define GPIO_VAL_VALUE 0x00 - #define GPIO_IRQ_ENABLE 0x00 - #define GPIO_IRQ_TYPE0 0x04 -@@ -150,9 +137,9 @@ enum aspeed_sgpio_reg { - #define GPIO_IRQ_TYPE2 0x0C - #define GPIO_IRQ_STATUS 0x10 - --static void __iomem *bank_reg(struct aspeed_sgpio *gpio, -- const struct aspeed_sgpio_bank *bank, -- const enum aspeed_sgpio_reg reg) -+static void __iomem *aspeed_sgpio_g4_bank_reg(struct aspeed_sgpio *gpio, -+ const struct aspeed_sgpio_bank *bank, -+ const enum aspeed_sgpio_reg reg) - { - switch (reg) { - case reg_val: -@@ -177,6 +164,30 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio, - } - } - -+static u32 aspeed_sgpio_g7_reg_mask(const enum aspeed_sgpio_reg reg) -+{ -+ switch (reg) { -+ case reg_val: -+ case reg_rdata: -+ return SGPIO_G7_OUT_DATA; -+ case reg_irq_enable: -+ return SGPIO_G7_IRQ_EN; -+ case reg_irq_type0: -+ return SGPIO_G7_IRQ_TYPE0; -+ case reg_irq_type1: -+ return SGPIO_G7_IRQ_TYPE1; -+ case reg_irq_type2: -+ return SGPIO_G7_IRQ_TYPE2; -+ case reg_irq_status: -+ return SGPIO_G7_IRQ_STS; -+ case reg_tolerance: -+ return SGPIO_G7_RST_TOLERANCE; -+ default: -+ WARN_ON_ONCE(1); -+ return 0; -+ } -+} -+ - #define GPIO_BANK(x) ((x) >> 6) - #define GPIO_OFFSET(x) ((x) & GENMASK(5, 0)) - #define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1) -@@ -215,40 +226,16 @@ static bool aspeed_sgpio_is_input(unsigned int offset) - return !(offset % 2); - } - --static bool aspeed_sgpios_ctrl_by_csr(unsigned int offset) --{ -- if (offset >= BMC_CONTROL_START_INDEX && -- offset <= BMC_CONTROL_END_INDEX) -- return true; -- return false; --} -- - static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_sgpio_bank *bank; -- void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -- unsigned long flags; - enum aspeed_sgpio_reg reg; - int rc = 0; - -- raw_spin_lock_irqsave(&gpio->lock, flags); -+ guard(raw_spinlock_irqsave)(&gpio->lock); - -- if (gpio->version == 7) { -- if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) -- reg = aspeed_sgpio_is_input(offset) ? -- SGPIO_G7_PARALLEL_IN_DATA : -- SGPIO_G7_PARALLEL_OUT_DATA; -- else -- reg = aspeed_sgpio_is_input(offset) ? SGPIO_G7_IN_DATA : -- SGPIO_G7_OUT_DATA; -- rc = !!(field_get(reg, ioread32(addr))); -- } else { -- bank = to_bank(offset); -- reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; -- rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); -- } -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; -+ rc = gpio->pdata->llops->reg_bit_get(gpio, offset, reg); - - return rc; - } -@@ -256,58 +243,11 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) - static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -- const struct aspeed_sgpio_bank *bank = to_bank(offset); -- void __iomem *addr_r, *addr_w; -- u32 reg = 0; -- -- if (aspeed_sgpio_is_input(offset)) -- return -EINVAL; -- -- /* Since this is an output, read the cached value from rdata, then -- * update val. */ -- addr_r = bank_reg(gpio, bank, reg_rdata); -- addr_w = bank_reg(gpio, bank, reg_val); -- -- reg = ioread32(addr_r); -- -- if (val) -- reg |= GPIO_BIT(offset); -- else -- reg &= ~GPIO_BIT(offset); -- -- iowrite32(reg, addr_w); -- -- return 0; --} -- --static int sgpio_g7_set_value(struct gpio_chip *gc, unsigned int offset, -- int val) --{ -- struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -- void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -- u32 reg = 0, out_data; - - if (aspeed_sgpio_is_input(offset)) - return -EINVAL; - -- if (gpio->pdata->slave && !aspeed_sgpios_ctrl_by_csr(offset)) { -- // Ensure the parallel out value control by the software. -- ast_write_bits(addr, SGPIO_G7_PARALLEL_OUT_SEL, -- SELECT_FROM_CSR); -- out_data = SGPIO_G7_PARALLEL_OUT_DATA; -- } else { -- // Ensure the serial out value control by the software. -- ast_write_bits(addr, SGPIO_G7_SERIAL_OUT_SEL, SELECT_FROM_CSR); -- out_data = SGPIO_G7_OUT_DATA; -- } -- reg = ioread32(addr); -- -- if (val) -- reg |= out_data; -- else -- reg &= ~out_data; -- -- iowrite32(reg, addr); -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val); - - return 0; - } -@@ -315,16 +255,11 @@ static int sgpio_g7_set_value(struct gpio_chip *gc, unsigned int offset, - static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -- unsigned long flags; -- -- raw_spin_lock_irqsave(&gpio->lock, flags); - -- if (gpio->version == 7) -- sgpio_g7_set_value(gc, offset, val); -- else -- sgpio_set_value(gc, offset, val); -+ guard(raw_spinlock_irqsave)(&gpio->lock); -+ sgpio_set_value(gc, offset, val); - -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ return; - } - - static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) -@@ -335,18 +270,14 @@ static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) - static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -- unsigned long flags; - int rc; - - /* No special action is required for setting the direction; we'll - * error-out in sgpio_set_value if this isn't an output GPIO */ - -- raw_spin_lock_irqsave(&gpio->lock, flags); -- if (gpio->version == 7) -- rc = sgpio_g7_set_value(gc, offset, val); -- else -- rc = sgpio_set_value(gc, offset, val); -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ guard(raw_spinlock_irqsave)(&gpio->lock); -+ -+ rc = sgpio_set_value(gc, offset, val); - - return rc; - } -@@ -356,132 +287,34 @@ static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) - return !!aspeed_sgpio_is_input(offset); - } - --static void irqd_to_aspeed_sgpio_data(struct irq_data *d, -- struct aspeed_sgpio **gpio, -- const struct aspeed_sgpio_bank **bank, -- u32 *bit, int *offset) --{ -- struct aspeed_sgpio *internal; -- -- *offset = irqd_to_hwirq(d); -- internal = irq_data_get_irq_chip_data(d); -- WARN_ON(!internal); -- -- *gpio = internal; -- *bank = to_bank(*offset); -- *bit = GPIO_BIT(*offset); --} -- --static void irqd_to_aspeed_g7_sgpio_data(struct irq_data *d, -- struct aspeed_sgpio **gpio, -- int *offset) --{ -- struct aspeed_sgpio *internal; -- -- *offset = irqd_to_hwirq(d); -- internal = irq_data_get_irq_chip_data(d); -- WARN_ON(!internal); -- -- *gpio = internal; --} - - static void aspeed_sgpio_irq_ack(struct irq_data *d) - { -- const struct aspeed_sgpio_bank *bank; -- struct aspeed_sgpio *gpio; -- unsigned long flags; -- void __iomem *status_addr; -- int offset; -- u32 bit; -- -- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -- -- status_addr = bank_reg(gpio, bank, reg_irq_status); -+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); -+ int offset = irqd_to_hwirq(d); - -- raw_spin_lock_irqsave(&gpio->lock, flags); -+ guard(raw_spinlock_irqsave)(&gpio->lock); - -- iowrite32(bit, status_addr); -- -- raw_spin_unlock_irqrestore(&gpio->lock, flags); --} -- --static void aspeed_g7_sgpio_irq_ack(struct irq_data *d) --{ -- struct aspeed_sgpio *gpio; -- unsigned long flags; -- void __iomem *status_addr; -- int offset; -- -- irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -- -- status_addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -- -- raw_spin_lock_irqsave(&gpio->lock, flags); -- -- ast_write_bits(status_addr, SGPIO_G7_IRQ_STS, 1); -- -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); - } - - static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) - { -- const struct aspeed_sgpio_bank *bank; -- struct aspeed_sgpio *gpio; -- unsigned long flags; -- u32 reg, bit; -- void __iomem *addr; -- int offset; -- -- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -- addr = bank_reg(gpio, bank, reg_irq_enable); -+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); -+ int offset = irqd_to_hwirq(d); - - /* Unmasking the IRQ */ - if (set) -- gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); -- -- raw_spin_lock_irqsave(&gpio->lock, flags); -- -- reg = ioread32(addr); -- if (set) -- reg |= bit; -- else -- reg &= ~bit; -- -- iowrite32(reg, addr); -- -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -- -- /* Masking the IRQ */ -- if (!set) -- gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); -- -- --} -- --static void aspeed_g7_sgpio_irq_set_mask(struct irq_data *d, bool set) --{ -- struct aspeed_sgpio *gpio; -- unsigned long flags; -- void __iomem *addr; -- int offset; -- -- irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -- addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -- -- /* Unmasking the IRQ */ -- if (set) -- gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); -- -- raw_spin_lock_irqsave(&gpio->lock, flags); -- if (set) -- ast_write_bits(addr, SGPIO_G7_IRQ_EN, 1); -- else -- ast_clr_bits(addr, SGPIO_G7_IRQ_EN); -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ gpiochip_enable_irq(&gpio->chip, offset); -+ scoped_guard(raw_spinlock_irqsave, &gpio->lock) -+ { -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_enable, -+ set); -+ } - - /* Masking the IRQ */ - if (!set) -- gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); -+ gpiochip_disable_irq(&gpio->chip, offset); - } - - static void aspeed_sgpio_irq_mask(struct irq_data *d) -@@ -494,89 +327,14 @@ static void aspeed_sgpio_irq_unmask(struct irq_data *d) - aspeed_sgpio_irq_set_mask(d, true); - } - --static void aspeed_g7_sgpio_irq_mask(struct irq_data *d) --{ -- aspeed_g7_sgpio_irq_set_mask(d, false); --} -- --static void aspeed_g7_sgpio_irq_unmask(struct irq_data *d) --{ -- aspeed_g7_sgpio_irq_set_mask(d, true); --} -- - static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) - { - u32 type0 = 0; - u32 type1 = 0; - u32 type2 = 0; -- u32 bit, reg; -- const struct aspeed_sgpio_bank *bank; - irq_flow_handler_t handler; -- struct aspeed_sgpio *gpio; -- unsigned long flags; -- void __iomem *addr; -- int offset; -- -- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -- -- switch (type & IRQ_TYPE_SENSE_MASK) { -- case IRQ_TYPE_EDGE_BOTH: -- type2 |= bit; -- fallthrough; -- case IRQ_TYPE_EDGE_RISING: -- type0 |= bit; -- fallthrough; -- case IRQ_TYPE_EDGE_FALLING: -- handler = handle_edge_irq; -- break; -- case IRQ_TYPE_LEVEL_HIGH: -- type0 |= bit; -- fallthrough; -- case IRQ_TYPE_LEVEL_LOW: -- type1 |= bit; -- handler = handle_level_irq; -- break; -- default: -- return -EINVAL; -- } -- -- raw_spin_lock_irqsave(&gpio->lock, flags); -- -- addr = bank_reg(gpio, bank, reg_irq_type0); -- reg = ioread32(addr); -- reg = (reg & ~bit) | type0; -- iowrite32(reg, addr); -- -- addr = bank_reg(gpio, bank, reg_irq_type1); -- reg = ioread32(addr); -- reg = (reg & ~bit) | type1; -- iowrite32(reg, addr); -- -- addr = bank_reg(gpio, bank, reg_irq_type2); -- reg = ioread32(addr); -- reg = (reg & ~bit) | type2; -- iowrite32(reg, addr); -- -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -- -- irq_set_handler_locked(d, handler); -- -- return 0; --} -- --static int aspeed_g7_sgpio_set_type(struct irq_data *d, unsigned int type) --{ -- u32 type0 = 0; -- u32 type1 = 0; -- u32 type2 = 0; -- irq_flow_handler_t handler; -- struct aspeed_sgpio *gpio; -- unsigned long flags; -- void __iomem *addr; -- int offset; -- -- irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -- addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); -+ int offset = irqd_to_hwirq(d); - - switch (type & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_EDGE_BOTH: -@@ -599,15 +357,14 @@ static int aspeed_g7_sgpio_set_type(struct irq_data *d, unsigned int type) - return -EINVAL; - } - -- raw_spin_lock_irqsave(&gpio->lock, flags); -- -- ast_write_bits(addr, SGPIO_G7_IRQ_TYPE2, type2); -- ast_write_bits(addr, SGPIO_G7_IRQ_TYPE1, type1); -- ast_write_bits(addr, SGPIO_G7_IRQ_TYPE0, type0); -- -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ scoped_guard(raw_spinlock_irqsave, &gpio->lock) { -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); -+ } - - irq_set_handler_locked(d, handler); -+ - return 0; - } - -@@ -616,64 +373,27 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc) - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct irq_chip *ic = irq_desc_get_chip(desc); - struct aspeed_sgpio *data = gpiochip_get_data(gc); -- unsigned int i, p; -- unsigned long reg; -- -- chained_irq_enter(ic, desc); -- -- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -- const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; -- -- reg = ioread32(bank_reg(data, bank, reg_irq_status)); -- -- for_each_set_bit(p, ®, 32) -- generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2); -- } -- -- chained_irq_exit(ic, desc); --} -- --static void aspeed_g7_sgpio_irq_handler(struct irq_desc *desc) --{ -- struct gpio_chip *gc = irq_desc_get_handler_data(desc); -- struct irq_chip *ic = irq_desc_get_chip(desc); -- struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned int i, p, banks; - unsigned long reg; -- void __iomem *addr; - - chained_irq_enter(ic, desc); - -- banks = DIV_ROUND_UP(gpio->chip.ngpio >> 1, 32); -+ banks = DIV_ROUND_UP(gc->ngpio, 64); - for (i = 0; i < banks; i++) { -- addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(i); -- -- reg = ioread32(addr); -+ reg = data->pdata->llops->reg_bank_get(data, i << 6, reg_irq_status); - - for_each_set_bit(p, ®, 32) - generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2); - } -+ - chained_irq_exit(ic, desc); - } - - static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) - { -- const struct aspeed_sgpio_bank *bank; -- struct aspeed_sgpio *gpio; -- u32 bit; -- int offset; -+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); - -- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -- seq_printf(p, dev_name(gpio->dev)); --} -- --static void aspeed_g7_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) --{ -- struct aspeed_sgpio *gpio; -- int offset; -- -- irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); -- seq_printf(p, dev_name(gpio->dev)); -+ seq_puts(p, dev_name(gpio->dev)); - } - - static const struct irq_chip aspeed_sgpio_irq_chip = { -@@ -686,21 +406,10 @@ static const struct irq_chip aspeed_sgpio_irq_chip = { - GPIOCHIP_IRQ_RESOURCE_HELPERS, - }; - --static const struct irq_chip aspeed_g7_sgpio_irq_chip = { -- .irq_ack = aspeed_g7_sgpio_irq_ack, -- .irq_mask = aspeed_g7_sgpio_irq_mask, -- .irq_unmask = aspeed_g7_sgpio_irq_unmask, -- .irq_set_type = aspeed_g7_sgpio_set_type, -- .irq_print_chip = aspeed_g7_sgpio_irq_print_chip, -- .flags = IRQCHIP_IMMUTABLE, -- GPIOCHIP_IRQ_RESOURCE_HELPERS, --}; -- - static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, - struct platform_device *pdev) - { - int rc, i; -- const struct aspeed_sgpio_bank *bank; - struct gpio_irq_chip *irq; - - rc = platform_get_irq(pdev, 0); -@@ -709,94 +418,110 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, - - gpio->irq = rc; - -- if (gpio->version != 7) -- /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ -- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -- bank = &aspeed_sgpio_banks[i]; -- /* disable irq enable bits */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); -- /* clear status bits */ -- iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); -- } -+ /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ -+ for (i = 0; i < gpio->chip.ngpio; i += 2) { -+ /* disable irq enable bits */ -+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_enable, 0); -+ /* clear status bits */ -+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_status, 1); -+ } - - irq = &gpio->chip.irq; -- if (gpio->version == 7) -- gpio_irq_chip_set_chip(irq, &aspeed_g7_sgpio_irq_chip); -- else -- gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip); -+ gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip); - irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask; - irq->handler = handle_bad_irq; - irq->default_type = IRQ_TYPE_NONE; -- irq->parent_handler = (gpio->version == 7) ? -- aspeed_g7_sgpio_irq_handler : -- aspeed_sgpio_irq_handler; -+ irq->parent_handler = aspeed_sgpio_irq_handler; - irq->parent_handler_data = gpio; - irq->parents = &gpio->irq; - irq->num_parents = 1; - -- if (gpio->version != 7) -- /* Apply default IRQ settings */ -- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -- bank = &aspeed_sgpio_banks[i]; -- /* set falling or level-low irq */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); -- /* trigger type is edge */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); -- /* single edge trigger */ -- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); -- } -+ /* Apply default IRQ settings */ -+ for (i = 0; i < gpio->chip.ngpio; i += 2) { -+ /* set falling or level-low irq */ -+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type0, 0); -+ /* trigger type is edge */ -+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type1, 0); -+ /* single edge trigger */ -+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type2, 0); -+ } - - return 0; - } - --static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { -- .pin_mask = GENMASK(9, 6), -- .ctrl_reg = 0x54, --}; -- --static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, -- unsigned int offset, bool enable) -+static void aspeed_sgpio_g4_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg, bool val) - { -- struct aspeed_sgpio *gpio = gpiochip_get_data(chip); -- unsigned long flags; -- void __iomem *reg; -- u32 val; -+ const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); -+ u32 temp; -+ -+ if (reg == reg_val) { -+ /* Since this is an output, read the cached value from rdata, then update val. */ -+ addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_rdata); -+ temp = ioread32(addr); -+ if (val) -+ temp |= GPIO_BIT(offset); -+ else -+ temp &= ~GPIO_BIT(offset); - -- reg = bank_reg(gpio, to_bank(offset), reg_tolerance); -+ addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_val); -+ iowrite32(temp, addr); -+ } else if (reg == reg_irq_status) { -+ if (val) -+ iowrite32(GPIO_BIT(offset), addr); -+ } else { -+ /* When setting other registers, we read from the register itself */ -+ temp = ioread32(addr); -+ if (val) -+ temp |= GPIO_BIT(offset); -+ else -+ temp &= ~GPIO_BIT(offset); -+ iowrite32(temp, addr); -+ } -+} - -- raw_spin_lock_irqsave(&gpio->lock, flags); -+static bool aspeed_sgpio_g4_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) -+{ -+ const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); - -- val = readl(reg); -+ return !!(ioread32(addr) & GPIO_BIT(offset)); -+} - -- if (enable) -- val |= GPIO_BIT(offset); -- else -- val &= ~GPIO_BIT(offset); -+static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) -+{ -+ const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); - -- writel(val, reg); -+ if (reg == reg_irq_status) -+ return ioread32(addr); -+ else -+ return -EOPNOTSUPP; -+} - -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+static const struct aspeed_sgpio_llops aspeed_sgpio_g4_llops = { -+ .reg_bit_set = aspeed_sgpio_g4_reg_bit_set, -+ .reg_bit_get = aspeed_sgpio_g4_reg_bit_get, -+ .reg_bank_get = aspeed_sgpio_g4_reg_bank_get, -+}; - -- return 0; --} -+static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { -+ .pin_mask = GENMASK(9, 6), -+ .llops = &aspeed_sgpio_g4_llops, -+ .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET, -+}; - --static int aspeed_g7_sgpio_reset_tolerance(struct gpio_chip *chip, -- unsigned int offset, bool enable) -+static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, -+ unsigned int offset, bool enable) - { - struct aspeed_sgpio *gpio = gpiochip_get_data(chip); -- unsigned long flags; -- void __iomem *reg; - -- reg = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ guard(raw_spinlock_irqsave)(&gpio->lock); - -- raw_spin_lock_irqsave(&gpio->lock, flags); -- -- if (enable) -- ast_write_bits(reg, SGPIO_G7_RST_TOLERANCE, 1); -- else -- ast_clr_bits(reg, SGPIO_G7_RST_TOLERANCE); -- -- raw_spin_unlock_irqrestore(&gpio->lock, flags); -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); - - return 0; - } -@@ -804,37 +529,73 @@ static int aspeed_g7_sgpio_reset_tolerance(struct gpio_chip *chip, - static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, - unsigned long config) - { -- struct aspeed_sgpio *gpio = gpiochip_get_data(chip); - unsigned long param = pinconf_to_config_param(config); - u32 arg = pinconf_to_config_argument(config); - -- if (param == PIN_CONFIG_PERSIST_STATE) { -- if (gpio->version == 7) -- return aspeed_g7_sgpio_reset_tolerance(chip, offset, -- arg); -- else -- return aspeed_sgpio_reset_tolerance(chip, offset, arg); -- } -+ if (param == PIN_CONFIG_PERSIST_STATE) -+ return aspeed_sgpio_reset_tolerance(chip, offset, arg); - - return -ENOTSUPP; - } - - static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { - .pin_mask = GENMASK(10, 6), -- .ctrl_reg = 0x54, -+ .llops = &aspeed_sgpio_g4_llops, -+ .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET, - }; - --static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = { -- .pin_mask = GENMASK(11, 6), -- .ctrl_reg = 0x0, -- .version = 7, -+static void aspeed_sgpio_g7_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg, bool val) -+{ -+ u32 mask = aspeed_sgpio_g7_reg_mask(reg); -+ void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ u32 write_val; -+ -+ if (mask) { -+ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); -+ iowrite32(write_val, addr); -+ } -+} -+ -+static bool aspeed_sgpio_g7_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) -+{ -+ u32 mask = aspeed_sgpio_g7_reg_mask(reg); -+ void __iomem *addr; -+ -+ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); -+ if (reg == reg_val) -+ mask = SGPIO_G7_IN_DATA; -+ -+ if (mask) -+ return field_get(mask, ioread32(addr)); -+ else -+ return 0; -+} -+ -+static int aspeed_sgpio_g7_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) -+{ -+ void __iomem *addr; -+ -+ if (reg == reg_irq_status) { -+ addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(offset >> 6); -+ return ioread32(addr); -+ } else { -+ return -EOPNOTSUPP; -+ } -+} -+ -+static const struct aspeed_sgpio_llops aspeed_sgpio_g7_llops = { -+ .reg_bit_set = aspeed_sgpio_g7_reg_bit_set, -+ .reg_bit_get = aspeed_sgpio_g7_reg_bit_get, -+ .reg_bank_get = aspeed_sgpio_g7_reg_bank_get, - }; - --static const struct aspeed_sgpio_pdata ast2700_sgpios_pdata = { -+static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = { - .pin_mask = GENMASK(11, 6), -- .ctrl_reg = 0x0, -- .version = 7, -- .slave = 1, -+ .llops = &aspeed_sgpio_g7_llops, -+ .cfg_offset = ASPEED_SGPIO_G7_CFG_OFFSET, - }; - - static const struct of_device_id aspeed_sgpio_of_table[] = { -@@ -842,7 +603,6 @@ static const struct of_device_id aspeed_sgpio_of_table[] = { - { .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, }, - { .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, }, - { .compatible = "aspeed,ast2700-sgpiom", .data = &ast2700_sgpiom_pdata, }, -- { .compatible = "aspeed,ast2700-sgpios", .data = &ast2700_sgpios_pdata, }, - {} - }; - -@@ -853,8 +613,7 @@ static int aspeed_sgpio_probe(struct platform_device *pdev) - u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask; - struct aspeed_sgpio *gpio; - unsigned long apb_freq; -- void __iomem *addr; -- int rc, i; -+ int rc; - - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) -@@ -871,8 +630,6 @@ static int aspeed_sgpio_probe(struct platform_device *pdev) - return -EINVAL; - - pin_mask = gpio->pdata->pin_mask; -- gpio->version = gpio->pdata->version; -- - rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); - if (rc < 0) { - dev_err(&pdev->dev, "Could not read ngpios property\n"); -@@ -883,53 +640,41 @@ static int aspeed_sgpio_probe(struct platform_device *pdev) - return -EINVAL; - } - -- if (gpio->version == 7 && !gpio->pdata->slave) -- for (i = 0; i < nr_gpios; i++) { -- addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(i); -- ast_write_bits(addr, SGPIO_G7_SERIAL_OUT_SEL, -- SELECT_FROM_CSR); -- } -- -- if (!gpio->pdata->slave) { -- rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); -- if (rc < 0) { -- dev_err(&pdev->dev, "Could not read bus-frequency property\n"); -- return -EINVAL; -- } -- -- gpio->pclk = devm_clk_get(&pdev->dev, NULL); -- if (IS_ERR(gpio->pclk)) { -- dev_err(&pdev->dev, "devm_clk_get failed\n"); -- return PTR_ERR(gpio->pclk); -- } -- -- apb_freq = clk_get_rate(gpio->pclk); -- -- /* -- * From the datasheet, -- * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) -- * period = 2 * (GPIO254[31:16] + 1) / PCLK -- * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) -- * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) -- * frequency * 2 * (GPIO254[31:16] + 1) = PCLK -- * GPIO254[31:16] = PCLK / (frequency * 2) - 1 -- */ -- if (sgpio_freq == 0) -- return -EINVAL; -- -- sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; -- -- if (sgpio_clk_div > (1 << 16) - 1) -- return -EINVAL; -- -- gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; -- iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | -- gpio_cnt_regval | ASPEED_SGPIO_ENABLE, -- gpio->base + gpio->pdata->ctrl_reg); -- } else { -- iowrite32(ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->ctrl_reg); -+ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); -+ if (rc < 0) { -+ dev_err(&pdev->dev, "Could not read bus-frequency property\n"); -+ return -EINVAL; - } - -+ gpio->pclk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(gpio->pclk)) { -+ dev_err(&pdev->dev, "devm_clk_get failed\n"); -+ return PTR_ERR(gpio->pclk); -+ } -+ -+ apb_freq = clk_get_rate(gpio->pclk); -+ -+ /* -+ * From the datasheet, -+ * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) -+ * period = 2 * (GPIO254[31:16] + 1) / PCLK -+ * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) -+ * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) -+ * frequency * 2 * (GPIO254[31:16] + 1) = PCLK -+ * GPIO254[31:16] = PCLK / (frequency * 2) - 1 -+ */ -+ if (sgpio_freq == 0) -+ return -EINVAL; -+ -+ sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; -+ -+ if (sgpio_clk_div > (1 << 16) - 1) -+ return -EINVAL; -+ -+ gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; -+ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | -+ ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset); -+ - raw_spin_lock_init(&gpio->lock); - - gpio->chip.parent = &pdev->dev; -diff --git a/drivers/i3c/master/ast2600-i3c-master.c b/drivers/i3c/master/ast2600-i3c-master.c -index 066b5ee90..fabe1313f 100644 ---- a/drivers/i3c/master/ast2600-i3c-master.c -+++ b/drivers/i3c/master/ast2600-i3c-master.c -@@ -77,12 +77,16 @@ - #define ADDR_HID(x) ((x) & ADDR_HID_MASK) - - #define IBI_QUEUE_STATUS 0x18 -+#define IBI_QUEUE_STATUS_DATA_LEN(x) ((x) & GENMASK(7, 0)) - - #define IBI_SIR_REQ_REJECT 0x30 - #define INTR_STATUS_EN 0x40 - #define INTR_SIGNAL_EN 0x44 - #define INTR_IBI_THLD_STAT BIT(2) - -+#define QUEUE_STATUS_LEVEL 0x4c -+#define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24) -+ - #define PRESENT_STATE 0x54 - #define CM_TFR_STS GENMASK(13, 8) - #define CM_TFR_STS_MASTER_SERV_IBI 0xe -@@ -340,6 +344,20 @@ static void ast2600_i3c_gen_target_reset_pattern(struct dw_i3c_master *dw) - SDA_IN_SW_MODE_EN | SCL_IN_SW_MODE_EN, 0); - } - -+static void aspeed_i3c_drain_ibi_queue(struct dw_i3c_master *dw) -+{ -+ /* -+ * Clear the IBI queue to avoid any stale IBI data when -+ * re-enabling the controller. -+ */ -+ u32 ibi_status = readl(dw->regs + IBI_QUEUE_STATUS); -+ u8 length = IBI_QUEUE_STATUS_DATA_LEN(ibi_status); -+ int i, nwords = (length + 3) >> 2; -+ -+ for (i = 0; i < nwords; i++) -+ readl(dw->regs + IBI_QUEUE_STATUS); -+} -+ - static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) - { - u32 state; -@@ -348,7 +366,7 @@ static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) - * Clear the IBI queue to enable the hardware to generate SCL and - * begin detecting the T-bit low to stop reading IBI data. - */ -- readl(dw->regs + IBI_QUEUE_STATUS); -+ aspeed_i3c_drain_ibi_queue(dw); - state = FIELD_GET(CM_TFR_STS, readl(dw->regs + PRESENT_STATE)); - if (state == CM_TFR_STS_MASTER_SERV_IBI) - return false; -@@ -359,7 +377,8 @@ static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) - static void ast2600_i3c_gen_tbits_in(struct dw_i3c_master *dw) - { - struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -- bool is_idle; -+ bool is_halted; -+ u32 nibi, i; - int ret; - - regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -@@ -370,14 +389,21 @@ static void ast2600_i3c_gen_tbits_in(struct dw_i3c_master *dw) - regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), - SDA_IN_SW_MODE_VAL, 0); - ret = readx_poll_timeout_atomic(ast2600_i3c_fsm_exit_serv_ibi, dw, -- is_idle, is_idle, 0, 2000000); -+ is_halted, is_halted, 0, 2000000); - regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), - SDA_IN_SW_MODE_EN, 0); -- if (ret) -+ if (ret) { - dev_err(&dw->base.dev, - "Failed to exit the I3C fsm from %lx(MASTER_SERV_IBI): %d", - FIELD_GET(CM_TFR_STS, readl(dw->regs + PRESENT_STATE)), - ret); -+ } else { -+ /* Clear the dummy data generated in this recovery process */ -+ nibi = readl(dw->regs + QUEUE_STATUS_LEVEL); -+ nibi = QUEUE_STATUS_IBI_STATUS_CNT(nibi); -+ for (i = 0; i < nibi; i++) -+ aspeed_i3c_drain_ibi_queue(dw); -+ } - } - - static void ast2600_i3c_set_ibi_mdb(struct dw_i3c_master *dw, u8 mdb) -diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig -index 3f0afa73a..619d3fb51 100644 ---- a/drivers/irqchip/Kconfig -+++ b/drivers/irqchip/Kconfig -@@ -734,6 +734,9 @@ config APPLE_AIC - Support for the Apple Interrupt Controller found on Apple Silicon SoCs, - such as the M1. - -+config AST2700_IRQ -+ bool -+ - config MCHP_EIC - bool "Microchip External Interrupt Controller" - depends on ARCH_AT91 || COMPILE_TEST -diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c -index 7e8758db8..0902e3064 100644 ---- a/drivers/media/platform/aspeed/aspeed-video.c -+++ b/drivers/media/platform/aspeed/aspeed-video.c -@@ -612,6 +612,38 @@ static inline u32 _make_addr(dma_addr_t addr) - #endif - } - -+static void aspeed_video_support_vga_ctrl(struct aspeed_video *v, bool yes) -+{ -+ u32 val = yes ? BIT(0) : 0; -+ u32 reg; -+ -+ if (!v || v->version < 6) -+ return; -+ -+ if (v->version == 7) -+ reg = (v->id == 1) ? 0x914 : 0x904; -+ else -+ reg = 0x104; -+ -+ regmap_update_bits(v->scu, reg, BIT(0), val); -+} -+ -+static void aspeed_video_set_vga_on(struct aspeed_video *v, bool on) -+{ -+ u32 val = on ? BIT(1) : 0; -+ u32 reg; -+ -+ if (!v || v->version < 6) -+ return; -+ -+ if (v->version == 7) -+ reg = (v->id == 1) ? 0x914 : 0x904; -+ else -+ reg = 0x104; -+ -+ regmap_update_bits(v->scu, reg, BIT(1), val); -+} -+ - static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420) - { - int i; -@@ -1912,12 +1944,6 @@ static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) - if (i >= VIDEO_INPUT_MAX) - return -EINVAL; - -- if (i == video->input) -- return 0; -- -- if (vb2_is_busy(&video->queue)) -- return -EBUSY; -- - if (IS_ERR(video->scu)) { - v4l2_dbg(1, debug, &video->v4l2_dev, "%s: scu isn't ready for input-control\n", __func__); - return -EINVAL; -@@ -2480,6 +2506,8 @@ static int aspeed_video_start_streaming(struct vb2_queue *q, - int rc; - struct aspeed_video *video = vb2_get_drv_priv(q); - -+ aspeed_video_set_vga_on(video, true); -+ - video->sequence = 0; - video->perf.duration_max = 0; - video->perf.duration_min = 0xffffffff; -@@ -2505,6 +2533,8 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q) - int rc; - struct aspeed_video *video = vb2_get_drv_priv(q); - -+ aspeed_video_set_vga_on(video, false); -+ - clear_bit(VIDEO_STREAMING, &video->flags); - - rc = wait_event_timeout(video->wait, -@@ -2890,6 +2920,7 @@ static int aspeed_video_probe(struct platform_device *pdev) - const struct aspeed_video_config *config; - struct aspeed_video *video; - int rc; -+ bool vga_ctrl; - - video = devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL); - if (!video) -@@ -2938,6 +2969,11 @@ static int aspeed_video_probe(struct platform_device *pdev) - if (rc) - return rc; - -+ /* vga_ctrl is a property to say if VGA will be on/off with KVM */ -+ vga_ctrl = of_find_property(pdev->dev.of_node, "vga_ctrl", NULL) ? 1 : 0; -+ aspeed_video_support_vga_ctrl(video, vga_ctrl); -+ aspeed_video_set_vga_on(video, false); -+ - rc = aspeed_video_setup_video(video); - if (rc) { - clk_unprepare(video->vclk); -diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c -index 3ce28dbed..035fa1c2b 100644 ---- a/drivers/net/ethernet/faraday/ftgmac100.c -+++ b/drivers/net/ethernet/faraday/ftgmac100.c -@@ -27,6 +27,9 @@ - #include - #include - #include -+#include -+#include -+#include - #include - #include - -@@ -1862,12 +1865,377 @@ static bool ftgmac100_has_child_node(struct device_node *np, const char *name) - return ret; - } - -+static int ftgmac100_get_ast2600_rgmii_flag(u32 delay) -+{ -+ if ((delay > 500 && delay < 1500) || -+ (delay > 2500 && delay < 7500)) -+ return AST2600_RGMII_KEEP_DELAY; -+ -+ return AST2600_RGMII_DIS_DELAY; -+} -+ -+static int ftgmac100_check_ast2600_rgmii_delay(struct regmap *scu, -+ u32 delay_unit, -+ int mac_id, int dly_reg) -+{ -+ u32 delay_value; -+ u32 tx_delay; -+ u32 rx_delay; -+ int tx_flag; -+ int rx_flag; -+ -+ regmap_read(scu, dly_reg, &delay_value); -+ if (mac_id == 0 || mac_id == 2) { -+ tx_delay = FIELD_GET(ASPEED_MAC0_2_TX_DLY, delay_value); -+ rx_delay = FIELD_GET(ASPEED_MAC0_2_RX_DLY, delay_value); -+ } else { -+ tx_delay = FIELD_GET(ASPEED_MAC1_3_TX_DLY, delay_value); -+ rx_delay = FIELD_GET(ASPEED_MAC1_3_RX_DLY, delay_value); -+ } -+ -+ /* Due to the hardware design reason, for MAC2/3 on AST2600, -+ * the zero delay ns on RX is configured by setting value 0x1a. -+ * List as below: -+ * 0x1a, 0x1b, ... , 0x1f, 0x00, 0x01, ... , 0x19 -+ * Covert for calculation purpose. -+ * 0x00, 0x01, ... , 0x19, 0x1a, 0x1b, ... , 0x1f -+ */ -+ if (mac_id == 2 || mac_id == 3) -+ rx_delay = (rx_delay + 0x06) & 0x1f; -+ -+ tx_delay *= delay_unit; -+ rx_delay *= delay_unit; -+ -+ tx_flag = ftgmac100_get_ast2600_rgmii_flag(tx_delay); -+ rx_flag = ftgmac100_get_ast2600_rgmii_flag(rx_delay); -+ -+ if (tx_flag == AST2600_RGMII_KEEP_DELAY || -+ rx_flag == AST2600_RGMII_KEEP_DELAY) { -+ return AST2600_RGMII_KEEP_DELAY; -+ } -+ -+ return AST2600_RGMII_DIS_DELAY; -+} -+ -+static int ftgmac100_set_ast2600_rgmii_delay(struct ftgmac100 *priv, -+ s32 rgmii_tx_delay, -+ s32 rgmii_rx_delay, -+ phy_interface_t *phy_intf) -+{ -+ struct device *dev = priv->dev; -+ struct device_node *np; -+ u32 rgmii_delay_unit; -+ u32 rx_delay_index; -+ u32 tx_delay_index; -+ struct regmap *scu; -+ int dly_mask; -+ int dly_reg; -+ int mac_id; -+ int err; -+ -+ np = dev->of_node; -+ -+ err = of_get_phy_mode(np, phy_intf); -+ if (err) { -+ dev_err(priv->dev, "Failed to get phy mode: %d\n", err); -+ return err; -+ } -+ -+ scu = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); -+ if (IS_ERR(scu)) { -+ dev_err(dev, "failed to get aspeed,scu"); -+ return PTR_ERR(scu); -+ } -+ -+ /* According to the register base address to specify the corresponding -+ * values. -+ */ -+ switch (priv->res->start) { -+ case AST2600_MAC0_BASE_ADDR: -+ mac_id = 0; -+ rgmii_delay_unit = AST2600_MAC01_CLK_DLY_UNIT; -+ dly_reg = AST2600_MAC01_CLK_DLY; -+ break; -+ case AST2600_MAC1_BASE_ADDR: -+ mac_id = 1; -+ rgmii_delay_unit = AST2600_MAC01_CLK_DLY_UNIT; -+ dly_reg = AST2600_MAC01_CLK_DLY; -+ break; -+ case AST2600_MAC2_BASE_ADDR: -+ mac_id = 2; -+ rgmii_delay_unit = AST2600_MAC23_CLK_DLY_UNIT; -+ dly_reg = AST2600_MAC23_CLK_DLY; -+ break; -+ case AST2600_MAC3_BASE_ADDR: -+ mac_id = 3; -+ rgmii_delay_unit = AST2600_MAC23_CLK_DLY_UNIT; -+ dly_reg = AST2600_MAC23_CLK_DLY; -+ break; -+ default: -+ dev_err(dev, "Invalid mac base address"); -+ return -EINVAL; -+ } -+ -+ if (of_phy_is_fixed_link(np)) { -+ if (rgmii_tx_delay < 0 || rgmii_rx_delay < 0) { -+ dev_err(dev, -+ "Add rx/tx-internal-delay-ps for fixed-link\n"); -+ /* Keep original RGMII delay value*/ -+ return 0; -+ } -+ -+ /* Must have both of rx/tx-internal-delay-ps for fixed-link */ -+ goto conf_delay; -+ } -+ -+ if (*phy_intf == PHY_INTERFACE_MODE_RGMII_RXID || -+ *phy_intf == PHY_INTERFACE_MODE_RGMII_TXID) -+ goto out_warn; -+ -+ if (*phy_intf != PHY_INTERFACE_MODE_RGMII && -+ *phy_intf != PHY_INTERFACE_MODE_RGMII_ID) -+ return 0; -+ -+ /* Both rx/tx-internal-delay-ps are not existed. */ -+ if (rgmii_tx_delay < 0 && rgmii_rx_delay < 0) { -+ int flag; -+ -+ flag = ftgmac100_check_ast2600_rgmii_delay(scu, -+ rgmii_delay_unit, -+ mac_id, -+ dly_reg); -+ if (flag == AST2600_RGMII_KEEP_DELAY) -+ goto out_warn; -+ -+ if (*phy_intf == PHY_INTERFACE_MODE_RGMII) { -+ dev_err(dev, "Update phy-mode to 'rgmii-id'\n"); -+ /* Forced phy interface to RGMII_ID and MAC will disable -+ * RGMII delay. -+ */ -+ *phy_intf = PHY_INTERFACE_MODE_RGMII_ID; -+ } -+ } else { -+ /* Please refer to ethernet-controller.yaml. */ -+ if (*phy_intf == PHY_INTERFACE_MODE_RGMII && -+ (rgmii_tx_delay == 2000 || rgmii_rx_delay == 2000)) { -+ dev_warn(dev, -+ "RX/TX delay cannot set to 2000 on 'rgmii'\n"); -+ return -EINVAL; -+ } -+ } -+ -+ /* The value is negative, which means the rx/tx-internal-delay-ps -+ * property is not existed in dts. Therefore, set to default 0. -+ */ -+ if (rgmii_tx_delay < 0) -+ rgmii_tx_delay = 0; -+ if (rgmii_rx_delay < 0) -+ rgmii_rx_delay = 0; -+ -+conf_delay: -+ tx_delay_index = DIV_ROUND_CLOSEST(rgmii_tx_delay, rgmii_delay_unit); -+ if (tx_delay_index >= 32) { -+ dev_err(dev, "The %u ps of TX delay is out of range\n", -+ rgmii_tx_delay); -+ return -EINVAL; -+ } -+ -+ rx_delay_index = DIV_ROUND_CLOSEST(rgmii_rx_delay, rgmii_delay_unit); -+ if (rx_delay_index >= 32) { -+ dev_err(dev, "The %u ps of RX delay is out of range\n", -+ rgmii_rx_delay); -+ return -EINVAL; -+ } -+ -+ /* Due to the hardware design reason, for MAC2/3 on AST2600, the zero -+ * delay ns on RX is configured by setting value 0x1a. -+ * List as below: -+ * 0x1a -> 0 ns, 0x1b -> 0.25 ns, ... , 0x1f -> 1.25 ns, -+ * 0x00 -> 1.5 ns, 0x01 -> 1.75 ns, ... , 0x19 -> 7.75 ns, 0x1a -> 0 ns -+ */ -+ if (mac_id == 2 || mac_id == 3) -+ rx_delay_index = (AST2600_MAC23_RX_DLY_0_NS + rx_delay_index) & -+ AST2600_MAC_TX_RX_DLY_MASK; -+ -+ if (mac_id == 0 || mac_id == 2) { -+ dly_mask = ASPEED_MAC0_2_TX_DLY | ASPEED_MAC0_2_RX_DLY; -+ tx_delay_index = FIELD_PREP(ASPEED_MAC0_2_TX_DLY, tx_delay_index); -+ rx_delay_index = FIELD_PREP(ASPEED_MAC0_2_RX_DLY, rx_delay_index); -+ } else { -+ dly_mask = ASPEED_MAC1_3_TX_DLY | ASPEED_MAC1_3_RX_DLY; -+ tx_delay_index = FIELD_PREP(ASPEED_MAC1_3_TX_DLY, tx_delay_index); -+ rx_delay_index = FIELD_PREP(ASPEED_MAC1_3_RX_DLY, rx_delay_index); -+ } -+ -+ regmap_update_bits(scu, dly_reg, dly_mask, tx_delay_index | rx_delay_index); -+ -+ return 0; -+ -+out_warn: -+ /* Print the warning message. Keep the phy-mode and the RGMII delay value. */ -+ dev_warn(dev, "Update phy-mode to 'rgmii-id' and add rx/tx-internal-delay-ps\n"); -+ -+ return 0; -+} -+ -+static int ftgmac100_set_ast2700_rgmii_delay(struct ftgmac100 *priv, -+ s32 rgmii_tx_delay, -+ s32 rgmii_rx_delay) -+{ -+ struct device *dev = priv->dev; -+ struct device_node *np; -+ u32 rgmii_delay_tx_unit, rgmii_delay_rx_unit; -+ u32 rgmii_delay_tx_dis, rgmii_delay_rx_dis; -+ u32 tx_delay_index, rx_delay_index; -+ u32 reg_unit, reg_val; -+ struct regmap *scu; -+ int dly_mask; -+ int mac_id; -+ -+ np = dev->of_node; -+ -+ scu = syscon_regmap_lookup_by_phandle(np, "aspeed,scu"); -+ if (IS_ERR(scu)) { -+ dev_err(dev, "failed to get aspeed,scu"); -+ return PTR_ERR(scu); -+ } -+ -+ /* According to the register base address to specify the corresponding -+ * values. -+ */ -+ switch (priv->res->start) { -+ case AST2700_MAC0_BASE_ADDR: -+ mac_id = 0; -+ regmap_read(scu, AST2700_MAC0_DLY_UNIT, ®_unit); -+ regmap_read(scu, AST2700_MAC0_DLY_VAL, ®_val); -+ break; -+ case AST2700_MAC1_BASE_ADDR: -+ mac_id = 1; -+ regmap_read(scu, AST2700_MAC1_DLY_UNIT, ®_unit); -+ regmap_read(scu, AST2700_MAC1_DLY_VAL, ®_val); -+ break; -+ case AST2700_MAC2_BASE_ADDR: -+ /* Only support SGMII */ -+ return 0; -+ default: -+ dev_err(dev, "Invalid mac base address"); -+ return -EINVAL; -+ } -+ -+ rgmii_delay_tx_unit = AST2700_MAC_TX_DLY_UNIT(reg_unit); -+ rgmii_delay_rx_unit = AST2700_MAC_RX_DLY_UNIT(reg_unit); -+ rgmii_delay_tx_dis = AST2700_MAC_TX_DLY_DIS(reg_val); -+ rgmii_delay_rx_dis = AST2700_MAC_RX_DLY_DIS(reg_val); -+ -+ /* The value is negative, which means the rx/tx-internal-delay-ps -+ * property is not existed in dts. Therefore, set to default 0. -+ */ -+ if (rgmii_tx_delay < 0) -+ rgmii_tx_delay = 0; -+ if (rgmii_rx_delay < 0) -+ rgmii_rx_delay = 0; -+ -+ tx_delay_index = DIV_ROUND_CLOSEST(rgmii_tx_delay, rgmii_delay_tx_unit); -+ tx_delay_index += rgmii_delay_tx_dis; -+ if (tx_delay_index >= 32) { -+ dev_err(dev, "The %u ps of TX delay is out of range\n", -+ rgmii_tx_delay); -+ return -EINVAL; -+ } -+ -+ rx_delay_index = DIV_ROUND_CLOSEST(rgmii_rx_delay, rgmii_delay_rx_unit); -+ rx_delay_index += rgmii_delay_rx_dis; -+ if (rx_delay_index >= 32) { -+ dev_err(dev, "The %u ps of RX delay is out of range\n", -+ rgmii_rx_delay); -+ return -EINVAL; -+ } -+ -+ if (mac_id == 0) { -+ dly_mask = ASPEED_MAC0_2_TX_DLY | ASPEED_MAC0_2_RX_DLY; -+ tx_delay_index = FIELD_PREP(ASPEED_MAC0_2_TX_DLY, tx_delay_index); -+ rx_delay_index = FIELD_PREP(ASPEED_MAC0_2_RX_DLY, rx_delay_index); -+ } else { -+ dly_mask = ASPEED_MAC1_3_TX_DLY | ASPEED_MAC1_3_RX_DLY; -+ tx_delay_index = FIELD_PREP(ASPEED_MAC1_3_TX_DLY, tx_delay_index); -+ rx_delay_index = FIELD_PREP(ASPEED_MAC1_3_RX_DLY, rx_delay_index); -+ } -+ -+ regmap_update_bits(scu, AST2700_MAC01_CLK_DLY, dly_mask, -+ tx_delay_index | rx_delay_index); -+ -+ return 0; -+} -+ -+static int ftgmac100_set_internal_delay(struct ftgmac100 *priv, -+ phy_interface_t *phy_intf) -+{ -+ struct device_node *np = priv->dev->of_node; -+ s32 rgmii_tx_delay; -+ s32 rgmii_rx_delay; -+ int err = 0; -+ -+ /* NCSI mode is based on RMII, not neet to set delay for RMII */ -+ if (of_get_property(np, "use-ncsi", NULL)) -+ return 0; -+ -+ /* AST2600 needs to know if the "tx/rx-internal-delay-ps" properties -+ * are existed in dts. If not existed, set -1 and delay is equal to 0. -+ */ -+ if (of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_tx_delay)) -+ rgmii_tx_delay = -1; -+ if (of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_rx_delay)) -+ rgmii_rx_delay = -1; -+ -+ if ((of_device_is_compatible(np, "aspeed,ast2600-mac"))) -+ err = ftgmac100_set_ast2600_rgmii_delay(priv, -+ rgmii_tx_delay, -+ rgmii_rx_delay, -+ phy_intf); -+ else if ((of_device_is_compatible(np, "aspeed,ast2700-mac"))) -+ err = ftgmac100_set_ast2700_rgmii_delay(priv, -+ rgmii_tx_delay, -+ rgmii_rx_delay); -+ -+ return err; -+} -+ -+static struct phy_device *ftgmac100_ast2600_phy_get(struct net_device *dev, -+ struct device_node *np, -+ void (*hndlr)(struct net_device *), -+ phy_interface_t phy_intf) -+{ -+ struct device_node *phy_np; -+ struct phy_device *phy; -+ int ret; -+ -+ if (of_phy_is_fixed_link(np)) { -+ ret = of_phy_register_fixed_link(np); -+ if (ret < 0) { -+ netdev_err(dev, "broken fixed-link specification\n"); -+ return NULL; -+ } -+ phy_np = of_node_get(np); -+ } else { -+ phy_np = of_parse_phandle(np, "phy-handle", 0); -+ if (!phy_np) -+ return NULL; -+ } -+ -+ phy = of_phy_connect(dev, phy_np, hndlr, 0, phy_intf); -+ -+ of_node_put(phy_np); -+ -+ return phy; -+} -+ - static int ftgmac100_probe(struct platform_device *pdev) - { - struct resource *res; - int irq; - struct net_device *netdev; - struct phy_device *phydev; -+ phy_interface_t phy_intf; - struct ftgmac100 *priv; - struct device_node *np; - int err = 0; -@@ -1937,6 +2305,10 @@ static int ftgmac100_probe(struct platform_device *pdev) - priv->rxdes0_edorr_mask = BIT(30); - priv->txdes0_edotr_mask = BIT(30); - priv->is_aspeed = true; -+ /* Configure RGMII delay if there are the corresponding compatibles */ -+ err = ftgmac100_set_internal_delay(priv, &phy_intf); -+ if (err) -+ goto err_phy_connect; - } else { - priv->rxdes0_edorr_mask = BIT(15); - priv->txdes0_edotr_mask = BIT(15); -@@ -1985,8 +2357,16 @@ static int ftgmac100_probe(struct platform_device *pdev) - goto err_setup_mdio; - } - -- phy = of_phy_get_and_connect(priv->netdev, np, -- &ftgmac100_adjust_link); -+ /* Because AST2600 will use the RGMII delay to determine -+ * which phy interface to use. -+ */ -+ if (of_device_is_compatible(np, "aspeed,ast2600-mac")) -+ phy = ftgmac100_ast2600_phy_get(priv->netdev, np, -+ &ftgmac100_adjust_link, -+ phy_intf); -+ else -+ phy = of_phy_get_and_connect(priv->netdev, np, -+ &ftgmac100_adjust_link); - if (!phy) { - dev_err(&pdev->dev, "Failed to connect to phy\n"); - err = -EINVAL; -diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h -index f8c30a09d..73cdd1a1b 100644 ---- a/drivers/net/ethernet/faraday/ftgmac100.h -+++ b/drivers/net/ethernet/faraday/ftgmac100.h -@@ -281,4 +281,43 @@ struct ftgmac100_rxdes { - #define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27) - - #define FTGMAC100_RXDES2_RXBUF_BADR_HI GENMASK(18, 16) -+ -+/* Aspeed SCU */ -+#define AST2600_MAC01_CLK_DLY 0x340 -+#define AST2600_MAC23_CLK_DLY 0x350 -+#define AST2600_MAC01_CLK_DLY_UNIT 45 /* ps */ -+#define AST2600_MAC01_TX_DLY_0_NS 0 -+#define AST2600_MAC01_RX_DLY_0_NS 0 -+#define AST2600_MAC23_CLK_DLY_UNIT 250 /* ps */ -+#define AST2600_MAC23_TX_DLY_0_NS 0 -+#define AST2600_MAC23_RX_DLY_0_NS 0x1a -+#define AST2600_MAC_TX_RX_DLY_MASK 0x1f -+#define ASPEED_MAC0_2_TX_DLY GENMASK(5, 0) -+#define ASPEED_MAC0_2_RX_DLY GENMASK(17, 12) -+#define ASPEED_MAC1_3_TX_DLY GENMASK(11, 6) -+#define ASPEED_MAC1_3_RX_DLY GENMASK(23, 18) -+ -+#define AST2600_MAC0_BASE_ADDR 0x1e660000 -+#define AST2600_MAC1_BASE_ADDR 0x1e680000 -+#define AST2600_MAC2_BASE_ADDR 0x1e670000 -+#define AST2600_MAC3_BASE_ADDR 0x1e690000 -+ -+/* Keep original delay */ -+#define AST2600_RGMII_KEEP_DELAY 0x01 -+/* Need to disable delay on MAC side */ -+#define AST2600_RGMII_DIS_DELAY 0x02 -+ -+#define AST2700_MAC0_DLY_UNIT 0x190 -+#define AST2700_MAC_TX_DLY_UNIT(x) FIELD_GET(GENMASK(15, 0), (x)) -+#define AST2700_MAC_RX_DLY_UNIT(x) FIELD_GET(GENMASK(31, 16), (x)) -+#define AST2700_MAC0_DLY_VAL 0x194 -+#define AST2700_MAC_TX_DLY_DIS(x) FIELD_GET(GENMASK(7, 0), (x)) -+#define AST2700_MAC_RX_DLY_DIS(x) FIELD_GET(GENMASK(23, 16), (x)) -+#define AST2700_MAC1_DLY_UNIT 0x198 -+#define AST2700_MAC1_DLY_VAL 0x19c -+#define AST2700_MAC01_CLK_DLY 0x390 -+#define AST2700_MAC0_BASE_ADDR 0x14050000 -+#define AST2700_MAC1_BASE_ADDR 0x14060000 -+#define AST2700_MAC2_BASE_ADDR 0x14070000 -+ - #endif /* __FTGMAC100_H */ -diff --git a/drivers/net/mctp/mctp-pcie-vdm.c b/drivers/net/mctp/mctp-pcie-vdm.c -index e89a296af..f715fc085 100644 ---- a/drivers/net/mctp/mctp-pcie-vdm.c -+++ b/drivers/net/mctp/mctp-pcie-vdm.c -@@ -33,7 +33,8 @@ - #include - #include - --#define MCTP_PCIE_VDM_MIN_MTU 64 -+// 64bytes mctp payload + 4bytes mctp header -+#define MCTP_PCIE_VDM_MIN_MTU (64 + 4) - #define MCTP_PCIE_VDM_MAX_MTU 512 - /* 16byte */ - #define MCTP_PCIE_VDM_HDR_SIZE 16 -@@ -311,12 +312,9 @@ void mctp_pcie_vdm_receive_packet(struct net_device *ndev) - - cb = __mctp_cb(skb); - cb->halen = 3; // route type | bdf address -- cb->haddr[0] = vdm_hdr->route_type; -- // address is also converted to little-endian, but we want to keep it as big-endian -- // because kernel network layer assumes address in big-endian format -- cb->haddr[1] = vdm_hdr->pci_req_id & 0xFF; -- cb->haddr[2] = vdm_hdr->pci_req_id >> 8; -- -+ cb->haddr[0] = vdm_hdr->route_type & GENMASK(2, 0); -+ cb->haddr[1] = vdm_hdr->pci_req_id >> 8; -+ cb->haddr[2] = vdm_hdr->pci_req_id & 0xFF; - net_status = netif_rx(skb); - if (net_status == NET_RX_SUCCESS) { - stats->rx_packets++; -diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c -index 2196aaf47..c171e39f5 100644 ---- a/drivers/rtc/rtc-aspeed.c -+++ b/drivers/rtc/rtc-aspeed.c -@@ -301,21 +301,25 @@ static int aspeed_rtc_probe(struct platform_device *pdev) - * In rtc_read_time, run aspeed_rtc_read_time and check the rtc_time. - * As a result, need to enable and initialize RTC time. - * -+ * If the RTC_ENABLE has been set, it means that the RTC has been initialed - * Enable and unlock RTC to initialize RTC time to 1970-01-01T01:01:01 - * and re-lock and ensure enable is set now that a time is programmed. - */ - ctrl = readl(rtc->base + RTC_CTRL); -- writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL); - -- /* -- * Initial value set to year:70,mon:0,mday:1,hour:1,min:1,sec:1 -- * rtc_valid_tm check whether in suitable range or not. -- */ -- writel(0x01010101, rtc->base + RTC_TIME); -- writel(0x00134601, rtc->base + RTC_YEAR); -+ if (!(ctrl & RTC_ENABLE)) { -+ writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL); - -- /* Re-lock and ensure enable is set now that a time is programmed */ -- writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL); -+ /* -+ * Initial value set to year:70,mon:0,mday:1,hour:1,min:1,sec:1 -+ * rtc_valid_tm check whether in suitable range or not. -+ */ -+ writel(0x01010101, rtc->base + RTC_TIME); -+ writel(0x00134601, rtc->base + RTC_YEAR); -+ -+ /* Re-lock and ensure enable is set now that a time is programmed */ -+ writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL); -+ } - - rc = devm_rtc_register_device(rtc->rtc_dev); - if (rc) { -diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c -index 64b9048e8..f230d602c 100644 ---- a/drivers/usb/gadget/udc/aspeed-vhub/core.c -+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c -@@ -257,6 +257,10 @@ void ast_vhub_init_hw(struct ast_vhub *vhub) - if (vhub->force_usb1) - ctrl |= VHUB_CTRL_FULL_SPEED_ONLY; - -+ /* Enlarge FIFO for ast2700 soc0 vhub1 */ -+ if (vhub->enlarge_fifo) -+ ctrl |= VHUB_CTRL_ENLARGE_FIFO; -+ - ctrl |= VHUB_CTRL_AUTO_REMOTE_WAKEUP; - ctrl |= VHUB_CTRL_UPSTREAM_CONNECT; - writel(ctrl, vhub->regs + AST_VHUB_CTRL); -@@ -454,6 +458,8 @@ static int ast_vhub_probe(struct platform_device *pdev) - if (!vhub->epns) - return -ENOMEM; - -+ vhub->enlarge_fifo = of_property_read_bool(np, "aspeed,enlarge-fifo"); -+ - spin_lock_init(&vhub->lock); - vhub->pdev = pdev; - vhub->port_irq_mask = GENMASK(VHUB_IRQ_DEV1_BIT + vhub->max_ports - 1, -diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h -index 78abf0a7c..1b710b8fd 100644 ---- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h -+++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h -@@ -35,6 +35,7 @@ - #define VHUB_CTRL_PHY_LOOP_TEST (1 << 25) - #define VHUB_CTRL_DN_PWN (1 << 24) - #define VHUB_CTRL_DP_PWN (1 << 23) -+#define VHUB_CTRL_ENLARGE_FIFO (1 << 21) - #define VHUB_CTRL_LONG_DESC (1 << 18) - #define VHUB_CTRL_ISO_RSP_CTRL (1 << 17) - #define VHUB_CTRL_SPLIT_IN (1 << 16) -@@ -429,6 +430,9 @@ struct ast_vhub { - /* Force full speed only */ - bool force_usb1 : 1; - -+ /* Enlarge FIFO for ast2700 soc0 vhub1 */ -+ bool enlarge_fifo : 1; -+ - /* Upstream bus speed captured at bus reset */ - unsigned int speed; - u8 current_config; --- -2.34.1 - diff --git a/patches-sonic/0003-aspeed-ast2700-shared-kernel-changes-update-to-6.12.94-00.07.04.patch b/patches-sonic/0003-aspeed-ast2700-shared-kernel-changes-update-to-6.12.94-00.07.04.patch new file mode 100644 index 000000000..997312d1c --- /dev/null +++ b/patches-sonic/0003-aspeed-ast2700-shared-kernel-changes-update-to-6.12.94-00.07.04.patch @@ -0,0 +1,1102 @@ +From: Chandrasekaran Swaminathan +Date: Wed, 09 Sep 2026 15:51:49 +0000 +Subject: [PATCH] Aspeed AST2700 support: modifications to shared/common kernel files + +Modifications to existing vendor-independent (shared/common) kernel +files - the common-code review surface (Kconfig/Makefile merges, +ftgmac100, pwm/core, clk-provider, pwm.h, videodev2.h), from a +fresh Aspeed merge at v00.07.04 on the 6.12.94 SONiC kernel. + +Signed-off-by: Chandrasekaran Swaminathan +--- +diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms +--- a/arch/arm64/Kconfig.platforms 2026-06-19 11:42:39.000000000 +0000 ++++ b/arch/arm64/Kconfig.platforms 2026-09-09 15:51:44.951234551 +0000 +@@ -40,6 +40,13 @@ + This enables support for Apple's in-house ARM SoC family, starting + with the Apple M1. + ++config ARCH_ASPEED ++ bool "Aspeed SoC family" ++ select AST2700_IRQ ++ help ++ Say yes if you intend to run on an Aspeed ast2700 or similar ++ seventh generation Aspeed BMCs. ++ + menuconfig ARCH_BCM + bool "Broadcom SoC Support" + +diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile +--- a/arch/arm64/boot/dts/Makefile 2026-09-09 15:51:11.436740996 +0000 ++++ b/arch/arm64/boot/dts/Makefile 2026-09-09 15:51:44.986234022 +0000 +@@ -9,6 +9,7 @@ + subdir-y += apm + subdir-y += apple + subdir-y += arm ++subdir-y += aspeed + subdir-y += bitmain + subdir-y += broadcom + subdir-y += cavium +diff --git a/crypto/Makefile b/crypto/Makefile +--- a/crypto/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/crypto/Makefile 2026-09-09 15:51:31.778433603 +0000 +@@ -181,6 +181,7 @@ + obj-$(CONFIG_CRYPTO_ECC) += ecc.o + obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o + obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o ++obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed_crypt.o + + ecdh_generic-y += ecdh.o + ecdh_generic-y += ecdh_helper.o +diff --git a/drivers/Makefile b/drivers/Makefile +--- a/drivers/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/Makefile 2026-09-09 15:51:35.330379930 +0000 +@@ -195,3 +195,4 @@ + obj-$(CONFIG_DPLL) += dpll/ + + obj-$(CONFIG_S390) += s390/ ++obj-$(CONFIG_JTAG_ASPEED) += jtag/ +diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig +--- a/drivers/bus/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/bus/Kconfig 2026-09-09 15:51:29.763464053 +0000 +@@ -261,6 +261,12 @@ + configuration. Allows to adjust the priorities of all master + peripherals. + ++config ASPEED_LTPI ++ bool "Aspeed LTPI bus controller driver" ++ depends on ARCH_ASPEED ++ help ++ LVDS Tunneling Protocol and Interface (LTPI) bus controller ++ + source "drivers/bus/fsl-mc/Kconfig" + source "drivers/bus/mhi/Kconfig" + +diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile +--- a/drivers/bus/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/bus/Makefile 2026-09-09 15:51:34.715389223 +0000 +@@ -39,6 +39,7 @@ + obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o + + obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o ++obj-$(CONFIG_ASPEED_LTPI) += aspeed-ltpi.o + + # MHI + obj-y += mhi/ +diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig +--- a/drivers/char/hw_random/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/char/hw_random/Kconfig 2026-09-09 15:51:30.808448261 +0000 +@@ -588,6 +588,21 @@ + + If unsure, say Y. + ++config HW_RANDOM_ASPEED ++ tristate "Aspeed Random Number Generator support" ++ depends on ARCH_ASPEED ++ default HW_RANDOM ++ help ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Aspeed ast2600/ast2700 devices. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called aspeed-rng. ++ ++ If unsure, say Y. ++ ++source "drivers/char/hw_random/dwc/Kconfig" ++ + endif # HW_RANDOM + + config UML_RANDOM +diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile +--- a/drivers/char/hw_random/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/char/hw_random/Makefile 2026-09-09 15:51:36.020369504 +0000 +@@ -50,3 +50,5 @@ + obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o + obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o + obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o ++obj-$(CONFIG_HW_RANDOM_ASPEED) += aspeed-rng.o ++obj-$(CONFIG_HW_RANDOM_DWC) += dwc/ +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +--- a/drivers/clk/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/clk/Kconfig 2026-09-09 15:51:28.136488639 +0000 +@@ -277,6 +277,20 @@ + The G4 and G5 series, including the ast2400 and ast2500, are supported + by this driver. + ++config COMMON_CLK_AST2700 ++ bool "Clock driver for AST2700 SoC" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ help ++ This driver provides support for clock on AST2700 SoC. ++ The driver is responsible for managing the various clocks required ++ by the peripherals and cores within the AST2700. ++ ++config COMMON_CLK_AST1700 ++ bool "Clock driver for AST1700" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ help ++ This driver supports the AST1700 clocks on the Aspeed BMC platforms. ++ + config COMMON_CLK_S2MPS11 + tristate "Clock driver for S2MPS1X/S5M8767 MFD" + depends on MFD_SEC_CORE || COMPILE_TEST +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +--- a/drivers/clk/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/clk/Makefile 2026-09-09 15:51:32.830417706 +0000 +@@ -48,6 +48,8 @@ + obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o + obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o + obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o ++obj-$(CONFIG_COMMON_CLK_AST2700) += clk-ast2700.o ++obj-$(CONFIG_COMMON_CLK_AST1700) += clk-ast1700.o + obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o + obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o + obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o +diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig +--- a/drivers/edac/Kconfig 2026-09-09 15:51:11.454740724 +0000 ++++ b/drivers/edac/Kconfig 2026-09-09 15:51:28.786478817 +0000 +@@ -520,6 +520,15 @@ + First, ECC must be configured in the bootloader. Then, this driver + will expose error counters via the EDAC kernel framework. + ++config EDAC_AST2700 ++ tristate "Aspeed AST2700 BMC SoC" ++ depends on ARCH_ASPEED ++ help ++ Support for error detection and correction on the Aspeed AST2700 ++ ++ First, ECC must be configured in the bootloader. Then, this driver ++ will expose error counters via the EDAC kernel framework. ++ + config EDAC_BLUEFIELD + tristate "Mellanox BlueField Memory ECC" + depends on ARM64 && ((MELLANOX_PLATFORM && ACPI) || COMPILE_TEST) +diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile +--- a/drivers/edac/Makefile 2026-09-09 15:51:11.454740724 +0000 ++++ b/drivers/edac/Makefile 2026-09-09 15:51:33.542406948 +0000 +@@ -83,6 +83,7 @@ + obj-$(CONFIG_EDAC_TI) += ti_edac.o + obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o + obj-$(CONFIG_EDAC_ASPEED) += aspeed_edac.o ++obj-$(CONFIG_EDAC_AST2700) += edac_ast2700.o + obj-$(CONFIG_EDAC_BLUEFIELD) += bluefield_edac.o + obj-$(CONFIG_EDAC_DMC520) += dmc520_edac.o + obj-$(CONFIG_EDAC_ELBA) += elba_edac.o +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +--- a/drivers/gpio/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpio/Kconfig 2026-09-09 15:51:30.550452160 +0000 +@@ -180,6 +180,14 @@ + help + Say Y here to support Aspeed AST2500 SGPIO functionality. + ++config GPIO_ASPEED_LTPI ++ bool "Aspeed LTPI GPIO support" ++ depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO ++ select GPIO_GENERIC ++ select GPIOLIB_IRQCHIP ++ help ++ Say Y here to support Aspeed AST2700 LTPI GPIO functionality. ++ + config GPIO_ATH79 + tristate "Atheros AR71XX/AR724X/AR913X GPIO support" + default y if ATH79 +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +--- a/drivers/gpio/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/gpio/Makefile 2026-09-09 15:51:35.743373689 +0000 +@@ -37,6 +37,7 @@ + obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o + obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o + obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o ++obj-$(CONFIG_GPIO_ASPEED_LTPI) += gpio-aspeed-ltpi.o + obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o + obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o + obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +--- a/drivers/hwmon/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/hwmon/Kconfig 2026-09-09 15:51:28.650480872 +0000 +@@ -423,6 +423,16 @@ + This driver can also be built as a module. If so, the module + will be called aspeed_g6_pwm_tach. + ++config SENSORS_ASPEED_CHASSIS ++ tristate "ASPEED CHASSIS Driver" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ help ++ This driver provides support for Aspeed ast2600 chassis intruded ++ detect support. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called aspeed-chassis. ++ + config SENSORS_ATXP1 + tristate "Attansic ATXP1 VID controller" + depends on I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +--- a/drivers/hwmon/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/hwmon/Makefile 2026-09-09 15:51:33.388409275 +0000 +@@ -55,6 +55,7 @@ + obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o + obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o + obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tach.o ++obj-$(CONFIG_SENSORS_ASPEED_CHASSIS) += aspeed-chassis.o + obj-$(CONFIG_SENSORS_ASUS_ROG_RYUJIN) += asus_rog_ryujin.o + obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o + obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +--- a/drivers/i2c/busses/Kconfig 2026-09-09 15:51:11.425741162 +0000 ++++ b/drivers/i2c/busses/Kconfig 2026-09-09 15:51:28.068489667 +0000 +@@ -421,6 +421,17 @@ + This driver can also be built as a module. If so, the module + will be called i2c-altera. + ++config I2C_AST2600 ++ tristate "Aspeed I2C v2 Controller" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ select I2C_SMBUS ++ help ++ If you say yes to this option, support will be included for the ++ Aspeed I2C controller with new register set. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-ast2600. ++ + config I2C_ASPEED + tristate "Aspeed I2C Controller" + depends on ARCH_ASPEED || COMPILE_TEST +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +--- a/drivers/i2c/busses/Makefile 2026-09-09 15:51:11.426741147 +0000 ++++ b/drivers/i2c/busses/Makefile 2026-09-09 15:51:32.739419081 +0000 +@@ -39,6 +39,7 @@ + obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o + obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o + obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o ++obj-$(CONFIG_I2C_AST2600) += i2c-ast2600.o + obj-$(CONFIG_I2C_AT91) += i2c-at91.o + i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o + ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y) +diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig +--- a/drivers/irqchip/Kconfig 2026-09-09 15:51:11.465740558 +0000 ++++ b/drivers/irqchip/Kconfig 2026-09-09 15:51:30.232456966 +0000 +@@ -735,6 +735,9 @@ + Support for the Apple Interrupt Controller found on Apple Silicon SoCs, + such as the M1. + ++config AST2700_IRQ ++ bool ++ + config MCHP_EIC + bool "Microchip External Interrupt Controller" + depends on ARCH_AT91 || COMPILE_TEST +diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile +--- a/drivers/irqchip/Makefile 2026-09-09 15:51:11.465740558 +0000 ++++ b/drivers/irqchip/Makefile 2026-09-09 15:51:35.390379023 +0000 +@@ -85,6 +85,8 @@ + obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o + obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o + obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o ++obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o irq-aspeed-intc.o irq-aspeed-e2m-ic.o ++obj-$(CONFIG_AST2700_IRQ) += irq-ast2700-intc0.o irq-ast2700-intc1.o + obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o + obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o + obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o +diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig +--- a/drivers/mailbox/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/mailbox/Kconfig 2026-09-09 15:51:30.484453157 +0000 +@@ -295,4 +295,12 @@ + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + ++config AST2700_MBOX ++ tristate "ASPEED AST2700 IPC driver" ++ depends on ARCH_ASPEED ++ help ++ Say y here to enable support for the AST2700 IPC mailbox driver, ++ providing an interface for invoking the inter-process communication ++ signals from the application processor to other masters. ++ + endif +diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile +--- a/drivers/mailbox/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/mailbox/Makefile 2026-09-09 15:51:35.677374687 +0000 +@@ -64,3 +64,5 @@ + obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o + + obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o ++ ++obj-$(CONFIG_AST2700_MBOX) += ast2700-mailbox.o +diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig +--- a/drivers/net/can/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/net/can/Kconfig 2026-09-09 15:51:29.478468360 +0000 +@@ -66,6 +66,12 @@ + + if CAN_NETLINK + ++config CAN_ASPEED ++ tristate "ASPEED CAN" ++ depends on ARM64 || COMPILE_TEST ++ help ++ ASPEED CAN driver. ++ + config CAN_CALC_BITTIMING + bool "CAN bit-timing calculation" + default y +diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile +--- a/drivers/net/can/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/net/can/Makefile 2026-09-09 15:51:34.404393922 +0000 +@@ -15,6 +15,7 @@ + obj-y += usb/ + obj-y += softing/ + ++obj-$(CONFIG_CAN_ASPEED) += aspeed_can.o + obj-$(CONFIG_CAN_AT91) += at91_can.o + obj-$(CONFIG_CAN_BXCAN) += bxcan.o + obj-$(CONFIG_CAN_CAN327) += can327.o +diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig +--- a/drivers/net/ethernet/faraday/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/net/ethernet/faraday/Kconfig 2026-09-09 15:51:44.742237709 +0000 +@@ -6,7 +6,7 @@ + config NET_VENDOR_FARADAY + bool "Faraday devices" + default y +- depends on ARM || COMPILE_TEST ++ depends on ARM || ARM64 || COMPILE_TEST + help + If you have a network (Ethernet) card belonging to this class, say Y. + +@@ -28,11 +28,10 @@ + + config FTGMAC100 + tristate "Faraday FTGMAC100 Gigabit Ethernet support" +- depends on ARM || COMPILE_TEST +- depends on !64BIT || BROKEN ++ depends on ARM || ARM64 || COMPILE_TEST + select PHYLIB + select FIXED_PHY +- select MDIO_ASPEED if MACH_ASPEED_G6 ++ select MDIO_ASPEED if ARCH_ASPEED + select CRC32 + help + This driver supports the FTGMAC100 Gigabit Ethernet controller +diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c +--- a/drivers/net/ethernet/faraday/ftgmac100.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/net/ethernet/faraday/ftgmac100.c 2026-09-09 15:51:44.742237709 +0000 +@@ -9,6 +9,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -19,12 +20,16 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include ++#include ++#include + #include + #include + +@@ -98,6 +103,7 @@ + struct work_struct reset_task; + struct mii_bus *mii_bus; + struct clk *clk; ++ struct reset_control *rst; + + /* AST2500/AST2600 RMII ref clock gate */ + struct clk *rclk; +@@ -119,6 +125,9 @@ + /* Misc */ + bool need_mac_restart; + bool is_aspeed; ++ ++ /* AST2700 SGMII */ ++ struct phy *sgmii; + }; + + static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr) +@@ -148,6 +157,29 @@ + { + u32 maccr = 0; + ++ /* Aspeed SoC needs SCU reset */ ++ if (priv->is_aspeed) { ++ int err; ++ ++ err = phy_reset(priv->sgmii); ++ if (err) { ++ dev_err(priv->dev, "Failed to reset sgmii\n"); ++ return err; ++ } ++ ++ err = reset_control_assert(priv->rst); ++ if (err) { ++ dev_err(priv->dev, "Failed to reset mac (%d)\n", err); ++ return err; ++ } ++ usleep_range(10000, 20000); ++ err = reset_control_deassert(priv->rst); ++ if (err) { ++ dev_err(priv->dev, "Failed to deassert mac reset (%d)\n", err); ++ return err; ++ } ++ } ++ + switch (priv->cur_speed) { + case SPEED_10: + case 0: /* no link */ +@@ -265,10 +297,12 @@ + iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR); + + /* Setup RX ring buffer base */ +- iowrite32(priv->rxdes_dma, priv->base + FTGMAC100_OFFSET_RXR_BADR); ++ iowrite32(lower_32_bits(priv->rxdes_dma), priv->base + FTGMAC100_OFFSET_RXR_BADR); ++ iowrite32(upper_32_bits(priv->rxdes_dma), priv->base + FTGMAC100_OFFSET_RXR_BADDR_HIGH); + + /* Setup TX ring buffer base */ +- iowrite32(priv->txdes_dma, priv->base + FTGMAC100_OFFSET_NPTXR_BADR); ++ iowrite32(lower_32_bits(priv->txdes_dma), priv->base + FTGMAC100_OFFSET_NPTXR_BADR); ++ iowrite32(upper_32_bits(priv->txdes_dma), priv->base + FTGMAC100_OFFSET_TXR_BADDR_HIGH); + + /* Configure RX buffer size */ + iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE), +@@ -321,6 +355,7 @@ + static void ftgmac100_start_hw(struct ftgmac100 *priv) + { + u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR); ++ struct phy_device *phydev = priv->netdev->phydev; + + /* Keep the original GMAC and FAST bits */ + maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE); +@@ -349,12 +384,18 @@ + if (priv->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) + maccr |= FTGMAC100_MACCR_RM_VLAN; + ++ if (of_device_is_compatible(priv->dev->of_node, "aspeed,ast2700-mac") && ++ phydev && phydev->interface == PHY_INTERFACE_MODE_RMII) ++ maccr |= FTGMAC100_MACCR_RMII_ENABLE; ++ + /* Hit the HW */ + iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); + } + + static void ftgmac100_stop_hw(struct ftgmac100 *priv) + { ++ phy_exit(priv->sgmii); ++ + iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR); + } + +@@ -425,7 +466,9 @@ + priv->rx_skbs[entry] = skb; + + /* Store DMA address into RX desc */ +- rxdes->rxdes3 = cpu_to_le32(map); ++ rxdes->rxdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI, ++ upper_32_bits(map))); ++ rxdes->rxdes3 = cpu_to_le32(lower_32_bits(map)); + + /* Ensure the above is ordered vs clearing the OWN bit */ + dma_wmb(); +@@ -551,7 +594,8 @@ + csum_vlan & 0xffff); + + /* Tear down DMA mapping, do necessary cache management */ +- map = le32_to_cpu(rxdes->rxdes3); ++ map = le32_to_cpu(rxdes->rxdes3) | ++ ((le32_to_cpu(rxdes->rxdes2) & FTGMAC100_RXDES2_RXBUF_BADR_HI) << 16); + + #if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU) + /* When we don't have an iommu, we can save cycles by not +@@ -628,9 +672,12 @@ + struct ftgmac100_txdes *txdes, + u32 ctl_stat) + { +- dma_addr_t map = le32_to_cpu(txdes->txdes3); ++ dma_addr_t map; + size_t len; + ++ map = le32_to_cpu(txdes->txdes3) | ++ ((le32_to_cpu(txdes->txdes2) & FTGMAC100_TXDES2_TXBUF_BADR_HI) << 16); ++ + if (ctl_stat & FTGMAC100_TXDES0_FTS) { + len = skb_headlen(skb); + dma_unmap_single(priv->dev, map, len, DMA_TO_DEVICE); +@@ -784,7 +831,9 @@ + f_ctl_stat |= FTGMAC100_TXDES0_FTS; + if (nfrags == 0) + f_ctl_stat |= FTGMAC100_TXDES0_LTS; +- txdes->txdes3 = cpu_to_le32(map); ++ txdes->txdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI, ++ upper_32_bits((ulong)map))); ++ txdes->txdes3 = cpu_to_le32(lower_32_bits(map)); + txdes->txdes1 = cpu_to_le32(csum_vlan); + + /* Next descriptor */ +@@ -812,7 +861,9 @@ + ctl_stat |= FTGMAC100_TXDES0_LTS; + txdes->txdes0 = cpu_to_le32(ctl_stat); + txdes->txdes1 = 0; +- txdes->txdes3 = cpu_to_le32(map); ++ txdes->txdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI, ++ upper_32_bits((ulong)map))); ++ txdes->txdes3 = cpu_to_le32(lower_32_bits(map)); + + /* Next one */ + pointer = ftgmac100_next_tx_pointer(priv, pointer); +@@ -887,7 +938,10 @@ + for (i = 0; i < priv->rx_q_entries; i++) { + struct ftgmac100_rxdes *rxdes = &priv->rxdes[i]; + struct sk_buff *skb = priv->rx_skbs[i]; +- dma_addr_t map = le32_to_cpu(rxdes->rxdes3); ++ dma_addr_t map; ++ ++ map = le32_to_cpu(rxdes->rxdes3) | ++ ((le32_to_cpu(rxdes->rxdes2) & FTGMAC100_RXDES2_RXBUF_BADR_HI) << 16); + + if (!skb) + continue; +@@ -944,19 +998,19 @@ + priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *), + GFP_KERNEL); + if (!priv->tx_skbs) +- goto err_free_rx_skbs; ++ return -ENOMEM; + + /* Allocate descriptors */ + priv->rxdes = dma_alloc_coherent(priv->dev, + MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes), + &priv->rxdes_dma, GFP_KERNEL); + if (!priv->rxdes) +- goto err_free_tx_skbs; ++ return -ENOMEM; + priv->txdes = dma_alloc_coherent(priv->dev, + MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes), + &priv->txdes_dma, GFP_KERNEL); + if (!priv->txdes) +- goto err_free_rxdes; ++ return -ENOMEM; + + /* Allocate scratch packet buffer */ + priv->rx_scratch = dma_alloc_coherent(priv->dev, +@@ -964,29 +1018,9 @@ + &priv->rx_scratch_dma, + GFP_KERNEL); + if (!priv->rx_scratch) +- goto err_free_txdes; ++ return -ENOMEM; + + return 0; +- +-err_free_txdes: +- dma_free_coherent(priv->dev, +- MAX_TX_QUEUE_ENTRIES * +- sizeof(struct ftgmac100_txdes), +- priv->txdes, priv->txdes_dma); +- priv->txdes = NULL; +-err_free_rxdes: +- dma_free_coherent(priv->dev, +- MAX_RX_QUEUE_ENTRIES * +- sizeof(struct ftgmac100_rxdes), +- priv->rxdes, priv->rxdes_dma); +- priv->rxdes = NULL; +-err_free_tx_skbs: +- kfree(priv->tx_skbs); +- priv->tx_skbs = NULL; +-err_free_rx_skbs: +- kfree(priv->rx_skbs); +- priv->rx_skbs = NULL; +- return -ENOMEM; + } + + static void ftgmac100_init_rings(struct ftgmac100 *priv) +@@ -1006,7 +1040,9 @@ + for (i = 0; i < priv->rx_q_entries; i++) { + rxdes = &priv->rxdes[i]; + rxdes->rxdes0 = 0; +- rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma); ++ rxdes->rxdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI, ++ upper_32_bits(priv->rx_scratch_dma))); ++ rxdes->rxdes3 = cpu_to_le32(lower_32_bits(priv->rx_scratch_dma)); + } + /* Mark the end of the ring */ + rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask); +@@ -1318,6 +1354,44 @@ + return work_done; + } + ++static int ftgmac100_init_sgmii(struct ftgmac100 *priv) ++{ ++ struct device_node *fixed_link_node = NULL; ++ int err; ++ ++ err = phy_init(priv->sgmii); ++ if (err) { ++ dev_err(priv->dev, "Failed to initialize sgmii\n"); ++ return err; ++ } ++ ++ /* If using fixed link in dts, sgmii need to be forced */ ++ fixed_link_node = of_get_child_by_name(priv->dev->of_node, "fixed-link"); ++ if (fixed_link_node) { ++ int speed; ++ ++ if (of_property_read_u32(fixed_link_node, "speed", &speed)) { ++ dev_err(priv->dev, "Failed to read speed from fixed-link node\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ err = phy_set_speed(priv->sgmii, speed); ++ if (err) ++ dev_err(priv->dev, "Failed to force sgmii speed\n"); ++ } else { ++ err = phy_set_speed(priv->sgmii, 0); ++ if (err) ++ dev_err(priv->dev, "Failed to enable sgmii Nway\n"); ++ } ++ ++err_out: ++ if (fixed_link_node) ++ of_node_put(fixed_link_node); ++ ++ return err; ++} ++ + static int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err) + { + int err = 0; +@@ -1342,6 +1416,9 @@ + /* Enable all interrupts */ + iowrite32(FTGMAC100_INT_ALL, priv->base + FTGMAC100_OFFSET_IER); + ++ /* Configure SGMII controller */ ++ ftgmac100_init_sgmii(priv); ++ + return err; + } + +@@ -1752,15 +1829,16 @@ + struct ftgmac100 *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; + +- if (!phydev) +- return; ++ devm_phy_put(priv->dev, priv->sgmii); + +- phy_disconnect(phydev); +- if (of_phy_is_fixed_link(priv->dev->of_node)) +- of_phy_deregister_fixed_link(priv->dev->of_node); ++ if (phydev) { ++ phy_disconnect(phydev); ++ if (of_phy_is_fixed_link(priv->dev->of_node)) ++ of_phy_deregister_fixed_link(priv->dev->of_node); + +- if (priv->use_ncsi) +- fixed_phy_unregister(phydev); ++ if (priv->use_ncsi) ++ fixed_phy_unregister(phydev); ++ } + } + + static void ftgmac100_destroy_mdio(struct net_device *netdev) +@@ -1903,7 +1981,8 @@ + np = pdev->dev.of_node; + if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") || + of_device_is_compatible(np, "aspeed,ast2500-mac") || +- of_device_is_compatible(np, "aspeed,ast2600-mac"))) { ++ of_device_is_compatible(np, "aspeed,ast2600-mac") || ++ of_device_is_compatible(np, "aspeed,ast2700-mac"))) { + priv->rxdes0_edorr_mask = BIT(30); + priv->txdes0_edotr_mask = BIT(30); + priv->is_aspeed = true; +@@ -1934,40 +2013,22 @@ + goto err_phy_connect; + } + err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link, +- PHY_INTERFACE_MODE_MII); ++ PHY_INTERFACE_MODE_RMII); + if (err) { + dev_err(&pdev->dev, "Connecting PHY failed\n"); + goto err_phy_connect; + } +- } else if (np && of_phy_is_fixed_link(np)) { +- struct phy_device *phy; +- +- err = of_phy_register_fixed_link(np); +- if (err) { +- dev_err(&pdev->dev, "Failed to register fixed PHY\n"); +- goto err_phy_connect; +- } +- +- phy = of_phy_get_and_connect(priv->netdev, np, +- &ftgmac100_adjust_link); +- if (!phy) { +- dev_err(&pdev->dev, "Failed to connect to fixed PHY\n"); +- of_phy_deregister_fixed_link(np); +- err = -EINVAL; +- goto err_phy_connect; +- } +- +- /* Display what we found */ +- phy_attached_info(phy); +- } else if (np && of_get_property(np, "phy-handle", NULL)) { ++ } else if (np && (of_phy_is_fixed_link(np) || ++ of_get_property(np, "phy-handle", NULL))) { + struct phy_device *phy; + + /* Support "mdio"/"phy" child nodes for ast2400/2500 with + * an embedded MDIO controller. Automatically scan the DTS for + * available PHYs and register them. + */ +- if (of_device_is_compatible(np, "aspeed,ast2400-mac") || +- of_device_is_compatible(np, "aspeed,ast2500-mac")) { ++ if (of_get_property(np, "phy-handle", NULL) && ++ (of_device_is_compatible(np, "aspeed,ast2400-mac") || ++ of_device_is_compatible(np, "aspeed,ast2500-mac"))) { + err = ftgmac100_setup_mdio(netdev); + if (err) + goto err_setup_mdio; +@@ -2016,6 +2077,24 @@ + if (of_device_is_compatible(np, "aspeed,ast2600-mac")) + iowrite32(FTGMAC100_TM_DEFAULT, + priv->base + FTGMAC100_OFFSET_TM); ++ ++ if (of_device_is_compatible(np, "aspeed,ast2700-mac")) { ++ if (netdev->phydev->interface == PHY_INTERFACE_MODE_SGMII) { ++ priv->sgmii = devm_phy_optional_get(&pdev->dev, "sgmii"); ++ if (IS_ERR(priv->sgmii)) { ++ dev_err(priv->dev, "Failed to get sgmii phy (%ld)\n", ++ PTR_ERR(priv->sgmii)); ++ err = PTR_ERR(priv->sgmii); ++ goto err_register_netdev; ++ } ++ } ++ } ++ } ++ ++ priv->rst = devm_reset_control_get_optional_exclusive(priv->dev, NULL); ++ if (IS_ERR(priv->rst)) { ++ err = PTR_ERR(priv->rst); ++ goto err_register_netdev; + } + + /* Default ring sizes */ +@@ -2042,6 +2121,12 @@ + netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM); + netdev->features |= netdev->hw_features; + ++ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); ++ if (err) { ++ dev_err(&pdev->dev, "64-bit DMA enable failed\n"); ++ goto err_register_netdev; ++ } ++ + /* register network device */ + err = register_netdev(netdev); + if (err) { +diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h +--- a/drivers/net/ethernet/faraday/ftgmac100.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/net/ethernet/faraday/ftgmac100.h 2026-09-09 15:51:44.742237709 +0000 +@@ -57,6 +57,13 @@ + #define FTGMAC100_OFFSET_RX_RUNT 0xc0 + #define FTGMAC100_OFFSET_RX_CRCER_FTL 0xc4 + #define FTGMAC100_OFFSET_RX_COL_LOST 0xc8 ++/* reserved 0xcc - 0x174 */ ++#define FTGMAC100_OFFSET_TXR_BADDR_LOW 0x178 /* ast2700 */ ++#define FTGMAC100_OFFSET_TXR_BADDR_HIGH 0x17c /* ast2700 */ ++#define FTGMAC100_OFFSET_HPTXR_BADDR_LOW 0x180 /* ast2700 */ ++#define FTGMAC100_OFFSET_HPTXR_BADDR_HIGH 0x184 /* ast2700 */ ++#define FTGMAC100_OFFSET_RXR_BADDR_LOW 0x188 /* ast2700 */ ++#define FTGMAC100_OFFSET_RXR_BADDR_HIGH 0x18C /* ast2700 */ + + /* + * Interrupt status register & interrupt enable register +@@ -166,6 +173,7 @@ + #define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16) + #define FTGMAC100_MACCR_RX_BROADPKT (1 << 17) + #define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18) ++#define FTGMAC100_MACCR_RMII_ENABLE BIT(20) /* defined in ast2700 */ + #define FTGMAC100_MACCR_FAST_MODE (1 << 19) + #define FTGMAC100_MACCR_SW_RST (1 << 31) + +@@ -225,6 +233,7 @@ + #define FTGMAC100_TXDES1_TX2FIC (1 << 30) + #define FTGMAC100_TXDES1_TXIC (1 << 31) + ++#define FTGMAC100_TXDES2_TXBUF_BADR_HI GENMASK(18, 16) + /* + * Receive descriptor, aligned to 16 bytes + */ +@@ -271,4 +280,6 @@ + #define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26) + #define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27) + ++#define FTGMAC100_RXDES2_RXBUF_BADR_HI GENMASK(18, 16) ++ + #endif /* __FTGMAC100_H */ +diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig +--- a/drivers/pci/controller/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pci/controller/Kconfig 2026-09-09 15:51:30.876447234 +0000 +@@ -47,6 +47,31 @@ + + If unsure, say Y if you have an Apple Silicon system. + ++config PHY_ASPEED_COMBINE_PERST ++ bool "ASPEED PCIe RC combine PERST with internal reset" ++ depends on ARCH_ASPEED ++ help ++ Configure PERST to connect with the internal PHY reset. When ++ this option is disabled, the driver selects the separate internal ++ PHY reset path by default. Enable it only on boards that require ++ PERST and the internal PHY reset to toggle at the same time. ++ ++config PCIE_ASPEED ++ bool "ASPEED PCIe controller" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ depends on OF ++ depends on PCI_MSI ++ select IRQ_MSI_LIB ++ help ++ Enable this option to support the PCIe controller found on ASPEED ++ SoCs. ++ ++ This driver provides initialization and management for PCIe ++ Root Complex functionality, including INTx and MSI support. ++ ++ Select Y if your platform uses an ASPEED SoC and requires PCIe ++ connectivity. ++ + config PCI_VERSATILE + bool "ARM Versatile PB PCI controller" + depends on ARCH_VERSATILE || COMPILE_TEST +diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile +--- a/drivers/pci/controller/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pci/controller/Makefile 2026-09-09 15:51:36.101368280 +0000 +@@ -39,6 +39,7 @@ + obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o + obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o + obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o ++obj-$(CONFIG_PCIE_ASPEED) += pcie-aspeed.o + + # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW + obj-y += dwc/ +diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig +--- a/drivers/phy/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/phy/Kconfig 2026-09-09 15:51:30.408454306 +0000 +@@ -84,6 +84,7 @@ + + source "drivers/phy/allwinner/Kconfig" + source "drivers/phy/amlogic/Kconfig" ++source "drivers/phy/aspeed/Kconfig" + source "drivers/phy/broadcom/Kconfig" + source "drivers/phy/cadence/Kconfig" + source "drivers/phy/freescale/Kconfig" +diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile +--- a/drivers/phy/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/phy/Makefile 2026-09-09 15:51:35.609375714 +0000 +@@ -13,6 +13,7 @@ + obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o + obj-y += allwinner/ \ + amlogic/ \ ++ aspeed/ \ + broadcom/ \ + cadence/ \ + freescale/ \ +diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c +--- a/drivers/pwm/core.c 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/pwm/core.c 2026-09-09 15:51:45.777222069 +0000 +@@ -426,9 +426,8 @@ + * chip. A negative error code is returned if the index is not valid for the + * specified PWM chip or if the PWM device cannot be requested. + */ +-static struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, +- unsigned int index, +- const char *label) ++struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, ++ unsigned int index, const char *label) + { + struct pwm_device *pwm; + int err; +@@ -446,6 +445,7 @@ + + return pwm; + } ++EXPORT_SYMBOL_GPL(pwm_request_from_chip); + + struct pwm_device * + of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args) +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +--- a/drivers/reset/Kconfig 2026-09-09 15:51:11.443740890 +0000 ++++ b/drivers/reset/Kconfig 2026-09-09 15:51:30.998445390 +0000 +@@ -22,6 +22,13 @@ + This option enables support for the external reset functions for + peripheral PHYs on the Altera Arria10 System Resource Chip. + ++config RESET_ASPEED ++ tristate "ASPEED Reset Driver" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ select AUXILIARY_BUS ++ help ++ This enables the reset controller driver for AST2700. ++ + config RESET_ATH79 + bool "AR71xx Reset Driver" if COMPILE_TEST + default ATH79 +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +--- a/drivers/reset/Makefile 2026-09-09 15:51:11.443740890 +0000 ++++ b/drivers/reset/Makefile 2026-09-09 15:51:36.220366481 +0000 +@@ -5,6 +5,7 @@ + obj-y += sti/ + obj-y += tegra/ + obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o ++obj-$(CONFIG_RESET_ASPEED) += reset-aspeed.o + obj-$(CONFIG_RESET_ATH79) += reset-ath79.o + obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o + obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +--- a/drivers/spi/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/spi/Kconfig 2026-09-09 15:51:30.595451480 +0000 +@@ -129,6 +129,16 @@ + controller (SPI) for the host firmware. The implementation + only supports SPI NOR. + ++config SPI_ASPEED_TXRX ++ tristate "Aspeed SPI controllers" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ depends on OF ++ help ++ This enables support for SPI controller driver in the Aspeed ++ AST2600, AST2500 and AST2400 SoCs when attached ++ to SPI device chips with half-duplex mode. On AST2700, ++ full-duplex mode can be enabled. ++ + config SPI_ATMEL + tristate "Atmel SPI Controller" + depends on ARCH_AT91 || COMPILE_TEST +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +--- a/drivers/spi/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/spi/Makefile 2026-09-09 15:51:35.786373039 +0000 +@@ -22,6 +22,7 @@ + obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o + obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o + obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o ++obj-$(CONFIG_SPI_ASPEED_TXRX) += spi-aspeed-txrx.o + obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o + obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o + obj-$(CONFIG_SPI_AT91_USART) += spi-at91-usart.o +diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig +--- a/drivers/tty/serial/8250/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/tty/serial/8250/Kconfig 2026-09-09 15:51:29.653465715 +0000 +@@ -256,6 +256,15 @@ + To compile this driver as a module, choose M here: the module + will be called 8250_accent. + ++config SERIAL_8250_ASPEED ++ tristate "Aspeed UART" ++ depends on SERIAL_8250 && ARCH_ASPEED ++ select ASPEED_UDMA ++ help ++ If you have a system using an Aspeed AST26xx SoCs and wish to ++ make use of its 16550A-compatible UART devices with DMA support, ++ say Y to this option. If unsure, say N. ++ + config SERIAL_8250_ASPEED_VUART + tristate "Aspeed Virtual UART" + depends on SERIAL_8250 +diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile +--- a/drivers/tty/serial/8250/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/tty/serial/8250/Makefile 2026-09-09 15:51:34.583391218 +0000 +@@ -21,6 +21,7 @@ + obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o + obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o + obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o ++obj-$(CONFIG_SERIAL_8250_ASPEED) += 8250_aspeed.o + obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o + obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o + obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o +diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig +--- a/drivers/ufs/host/Kconfig 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/ufs/host/Kconfig 2026-09-09 15:51:30.276456301 +0000 +@@ -143,3 +143,12 @@ + + Select this if you have UFS controller on Unisoc chipset. + If unsure, say N. ++ ++config SCSI_UFS_ASPEED ++ tristate "Aspeed specific hooks to UFS controller platform driver" ++ depends on SCSI_UFSHCD_PLATFORM ++ help ++ This selects the Aspeed specific additions to UFSHCD platform driver. ++ ++ Selects this if you have Aspeed platform with UFS controller. ++ If unsure, say N. +diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile +--- a/drivers/ufs/host/Makefile 2026-06-19 11:42:39.000000000 +0000 ++++ b/drivers/ufs/host/Makefile 2026-09-09 15:51:35.436378328 +0000 +@@ -12,3 +12,4 @@ + obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o + obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o + obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o ++obj-$(CONFIG_SCSI_UFS_ASPEED) += ufs-aspeed.o +diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h +--- a/include/linux/clk-provider.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/linux/clk-provider.h 2026-09-09 15:51:45.755222402 +0000 +@@ -623,6 +623,24 @@ + NULL, (flags), (reg), (bit_idx), \ + (clk_gate_flags), (lock)) + /** ++ * devm_clk_hw_register_gate_parent_hw - register a gate clock with the clock ++ * framework ++ * @dev: device that is registering this clock ++ * @name: name of this clock ++ * @parent_hw: pointer to parent clk ++ * @flags: framework-specific flags for this clock ++ * @reg: register address to control gating of this clock ++ * @bit_idx: which bit in the register controls gating of this clock ++ * @clk_gate_flags: gate-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++#define devm_clk_hw_register_gate_parent_hw(dev, name, parent_hw, flags, \ ++ reg, bit_idx, clk_gate_flags, \ ++ lock) \ ++ __devm_clk_hw_register_gate((dev), NULL, (name), NULL, (parent_hw), \ ++ NULL, (flags), (reg), (bit_idx), \ ++ (clk_gate_flags), (lock)) ++/** + * devm_clk_hw_register_gate_parent_data - register a gate clock with the + * clock framework + * @dev: device that is registering this clock +diff --git a/include/linux/pwm.h b/include/linux/pwm.h +--- a/include/linux/pwm.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/linux/pwm.h 2026-09-09 15:51:45.787221918 +0000 +@@ -405,6 +405,9 @@ + 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) + ++struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, ++ unsigned int index, const char *label); ++ + struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *chip, + const struct of_phandle_args *args); + struct pwm_device *of_pwm_single_xlate(struct pwm_chip *chip, +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +--- a/include/uapi/linux/videodev2.h 2026-06-19 11:42:39.000000000 +0000 ++++ b/include/uapi/linux/videodev2.h 2026-09-09 15:51:45.765222251 +0000 +@@ -880,6 +880,7 @@ + /* Flags */ + #define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA 0x00000001 + #define V4L2_PIX_FMT_FLAG_SET_CSC 0x00000002 ++#define V4L2_PIX_FMT_FLAG_PARTIAL_JPG 0x00000004 + + /* + * F O R M A T E N U M E R A T I O N diff --git a/patches-sonic/0003-i2c-designware-Support-stuck-SDA-line-recovery.patch b/patches-sonic/0003-i2c-designware-Support-stuck-SDA-line-recovery.patch index 550f39abc..dc71eec8a 100644 --- a/patches-sonic/0003-i2c-designware-Support-stuck-SDA-line-recovery.patch +++ b/patches-sonic/0003-i2c-designware-Support-stuck-SDA-line-recovery.patch @@ -42,9 +42,9 @@ index 2d32896..59d1eba 100644 #define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SCL_STUCK_AT_LOW 0xac +#define DW_IC_SDA_STUCK_AT_LOW 0xb0 + #define DW_IC_SMBUS_INTR_MASK 0xcc #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_VERSION 0xf8 - #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ @@ -98,6 +100,7 @@ #define DW_IC_INTR_GEN_CALL BIT(11) #define DW_IC_INTR_RESTART_DET BIT(12) diff --git a/patches-sonic/0004-arm64-dts-ac5-add-mmc-node-and-clock.patch b/patches-sonic/0004-arm64-dts-ac5-add-mmc-node-and-clock.patch deleted file mode 100644 index dddb78a76..000000000 --- a/patches-sonic/0004-arm64-dts-ac5-add-mmc-node-and-clock.patch +++ /dev/null @@ -1,84 +0,0 @@ -From cd40be983803830da19cb492b250abccf71ace7d Mon Sep 17 00:00:00 2001 -From: Elad Nachman -Date: Wed, 3 Jan 2024 19:28:03 +0200 -Subject: arm64: dts: ac5: add mmc node and clock - -Add mmc and mmc clock nodes to ac5 and ac5x device tree files - -Signed-off-by: Elad Nachman -Signed-off-by: Gregory CLEMENT ---- - arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi | 31 ++++++++++++++++++- - .../boot/dts/marvell/ac5-98dx35xx-rd.dts | 4 +++ - 2 files changed, 34 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -index b5e042b8e929..5591939e057b 100644 ---- a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -+++ b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi -@@ -77,7 +77,6 @@ soc { - #address-cells = <2>; - #size-cells = <2>; - ranges; -- dma-ranges; - - internal-regs@7f000000 { - #address-cells = <1>; -@@ -204,6 +203,30 @@ gpio1: gpio@18140 { - }; - }; - -+ mmc_dma: bus@80500000 { -+ compatible = "simple-bus"; -+ ranges; -+ #address-cells = <0x2>; -+ #size-cells = <0x2>; -+ reg = <0x0 0x80500000 0x0 0x100000>; -+ dma-ranges = <0x0 0x0 0x2 0x0 0x0 0x80000000>; -+ dma-coherent; -+ -+ sdhci: mmc@805c0000 { -+ compatible = "marvell,ac5-sdhci", -+ "marvell,armada-ap806-sdhci"; -+ reg = <0x0 0x805c0000 0x0 0x1000>; -+ interrupts = ; -+ clocks = <&emmc_clock>, <&cnm_clock>; -+ clock-names = "core", "axi"; -+ bus-width = <8>; -+ non-removable; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ mmc-hs400-1_8v; -+ }; -+ }; -+ - /* - * Dedicated section for devices behind 32bit controllers so we - * can configure specific DMA mapping for them -@@ -335,5 +358,11 @@ nand_clock: nand-clock { - #clock-cells = <0>; - clock-frequency = <400000000>; - }; -+ -+ emmc_clock: emmc-clock { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <400000000>; -+ }; - }; - }; -diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts b/arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts -index f0ebdb84eec9..0c973d7a215a 100644 ---- a/arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts -+++ b/arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts -@@ -99,3 +99,7 @@ parition@2 { - }; - }; - }; -+ -+&sdhci { -+ status = "okay"; -+}; --- -2.25.1 - diff --git a/patches-sonic/0005-arm64-traps-Call-platform-handler-for-do_serror.patch b/patches-sonic/0005-arm64-traps-Call-platform-handler-for-do_serror.patch index 9dbe58b22..77d9790c5 100644 --- a/patches-sonic/0005-arm64-traps-Call-platform-handler-for-do_serror.patch +++ b/patches-sonic/0005-arm64-traps-Call-platform-handler-for-do_serror.patch @@ -18,9 +18,9 @@ index 82cf1f8..1b22756 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -28,7 +28,7 @@ - void arm64_force_sig_fault_pkey(unsigned long far, const char *str, int pkey); - void arm64_force_sig_mceerr(int code, unsigned long far, short lsb, const char *str); - void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far, const char *str); + int reserved_fault_brk_handler(struct pt_regs *regs, unsigned long esr); + int kasan_brk_handler(struct pt_regs *regs, unsigned long esr); + int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr); - +int platform_serror(struct pt_regs *regs, unsigned int esr); int early_brk64(unsigned long addr, unsigned long esr, struct pt_regs *regs); diff --git a/patches-sonic/0006-mmc-xenon-Add-ac5-support-via-bounce-buffer.patch b/patches-sonic/0006-mmc-xenon-Add-ac5-support-via-bounce-buffer.patch deleted file mode 100644 index 83e4e7793..000000000 --- a/patches-sonic/0006-mmc-xenon-Add-ac5-support-via-bounce-buffer.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 5d40213347480e3ab903d5438dbd0d6b0110e6b8 Mon Sep 17 00:00:00 2001 -From: Elad Nachman -Date: Thu, 4 Jan 2024 19:30:33 +0200 -Subject: mmc: xenon: Add ac5 support via bounce buffer - -AC5/X/IM SOCs has a variant of the Xenon eMMC controller, -in which only 31-bit of addressing pass from the controller -on the AXI bus. -Since we cannot guarantee that only buffers from the first 2GB -of memory will reach the driver, the driver is configured for -SDMA mode, without 64-bit mode, overriding the DMA mask to 34-bit -to support the DDR memory mapping, which starts at offset 8GB. - -Signed-off-by: Elad Nachman -Acked-by: Adrian Hunter -Link: https://lore.kernel.org/r/20240104173033.2836110-1-enachman@marvell.com -Signed-off-by: Ulf Hansson ---- - drivers/mmc/host/sdhci-xenon.c | 31 +++++++++++++++++++++++++++++++ - drivers/mmc/host/sdhci-xenon.h | 3 ++- - 2 files changed, 33 insertions(+), 1 deletion(-) - -diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c -index 25ba7aecc3be..0e52867f6e91 100644 ---- a/drivers/mmc/host/sdhci-xenon.c -+++ b/drivers/mmc/host/sdhci-xenon.c -@@ -18,6 +18,8 @@ - #include - #include - #include -+#include -+#include - - #include "sdhci-pltfm.h" - #include "sdhci-xenon.h" -@@ -422,6 +424,7 @@ static int xenon_probe_params(struct platform_device *pdev) - struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); - u32 sdhc_id, nr_sdhc; - u32 tuning_count; -+ struct sysinfo si; - - /* Disable HS200 on Armada AP806 */ - if (priv->hw_version == XENON_AP806) -@@ -450,6 +453,23 @@ static int xenon_probe_params(struct platform_device *pdev) - } - priv->tuning_count = tuning_count; - -+ /* -+ * AC5/X/IM HW has only 31-bits passed in the crossbar switch. -+ * If we have more than 2GB of memory, this means we might pass -+ * memory pointers which are above 2GB and which cannot be properly -+ * represented. In this case, disable ADMA, 64-bit DMA and allow only SDMA. -+ * This effectively will enable bounce buffer quirk in the -+ * generic SDHCI driver, which will make sure DMA is only done -+ * from supported memory regions: -+ */ -+ if (priv->hw_version == XENON_AC5) { -+ si_meminfo(&si); -+ if (si.totalram * si.mem_unit > SZ_2G) { -+ host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; -+ host->quirks2 |= SDHCI_QUIRK2_BROKEN_64_BIT_DMA; -+ } -+ } -+ - return xenon_phy_parse_params(dev, host); - } - -@@ -562,6 +582,16 @@ static int xenon_probe(struct platform_device *pdev) - goto remove_sdhc; - - pm_runtime_put_autosuspend(&pdev->dev); -+ /* -+ * If we previously detected AC5 with over 2GB of memory, -+ * then we disable ADMA and 64-bit DMA. -+ * This means generic SDHCI driver has set the DMA mask to -+ * 32-bit. Since DDR starts at 0x2_0000_0000, we must use -+ * 34-bit DMA mask to access this DDR memory: -+ */ -+ if (priv->hw_version == XENON_AC5 && -+ host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) -+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); - - return 0; - -@@ -680,6 +710,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { - { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, - { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, - { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, -+ { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5}, - {} - }; - MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); -diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h -index 3e9c6c908a79..0460d97aad26 100644 ---- a/drivers/mmc/host/sdhci-xenon.h -+++ b/drivers/mmc/host/sdhci-xenon.h -@@ -57,7 +57,8 @@ enum xenon_variant { - XENON_A3700, - XENON_AP806, - XENON_AP807, -- XENON_CP110 -+ XENON_CP110, -+ XENON_AC5 - }; - - struct xenon_priv { --- -2.25.1 - diff --git a/patches-sonic/0007-usb-ehci-Add-support-for-ac5.patch b/patches-sonic/0007-usb-ehci-Add-support-for-ac5.patch deleted file mode 100644 index 48dfaf832..000000000 --- a/patches-sonic/0007-usb-ehci-Add-support-for-ac5.patch +++ /dev/null @@ -1,38 +0,0 @@ -From: Pavan Naregundi -Date: Mon, 13 Mar 2023 10:01:51 +0000 -usb: ehci: Add support for ac5 - -Add a new compatible string for 98DX25xx SoCs. -Change DMA bit mask to 64-bit addressing. - -Signed-off-by: Yuval Shaia -Tested-by: Raz Adashi -Reviewed-by: Raz Adashi ---- - drivers/usb/host/ehci-orion.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c -index 3626758b3..488a2ba86 100644 ---- a/drivers/usb/host/ehci-orion.c -+++ b/drivers/usb/host/ehci-orion.c -@@ -232,7 +232,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) - * set. Since shared usb code relies on it, set it here for - * now. Once we have dma capability bindings this can go away. - */ -- err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); -+ err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); - if (err) - goto err; - -@@ -341,6 +341,7 @@ static int ehci_orion_drv_remove(struct platform_device *pdev) - static const struct of_device_id ehci_orion_dt_ids[] = { - { .compatible = "marvell,orion-ehci", }, - { .compatible = "marvell,armada-3700-ehci", }, -+ { .compatible = "marvell,ac5-ehci", }, - {}, - }; - MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids); --- -2.25.1 - diff --git a/patches-sonic/PCI-ASPM-Fix-link-state-exit-during-switch-upstream.patch b/patches-sonic/PCI-ASPM-Fix-link-state-exit-during-switch-upstream.patch deleted file mode 100644 index 1b2cb4d8c..000000000 --- a/patches-sonic/PCI-ASPM-Fix-link-state-exit-during-switch-upstream.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Stodden -Date: Sun, 22 Dec 2024 19:39:08 -0800 -Subject: [PATCH] PCI/ASPM: Fix link state exit during switch upstream function - removal -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -[ Upstream commit cbf937dcadfd571a434f8074d057b32cd14fbea5 ] - -Before 456d8aa37d0f ("PCI/ASPM: Disable ASPM on MFD function removal to -avoid use-after-free"), we would free the ASPM link only after the last -function on the bus pertaining to the given link was removed. - -That was too late. If function 0 is removed before sibling function, -link->downstream would point to free'd memory after. - -After above change, we freed the ASPM parent link state upon any function -removal on the bus pertaining to a given link. - -That is too early. If the link is to a PCIe switch with MFD on the upstream -port, then removing functions other than 0 first would free a link which -still remains parent_link to the remaining downstream ports. - -The resulting GPFs are especially frequent during hot-unplug, because -pciehp removes devices on the link bus in reverse order. - -On that switch, function 0 is the virtual P2P bridge to the internal bus. -Free exactly when function 0 is removed -- before the parent link is -obsolete, but after all subordinate links are gone. - -Link: https://lore.kernel.org/r/e12898835f25234561c9d7de4435590d957b85d9.1734924854.git.dns@arista.com -Fixes: 456d8aa37d0f ("PCI/ASPM: Disable ASPM on MFD function removal to avoid use-after-free") -Signed-off-by: Daniel Stodden -Signed-off-by: Bjorn Helgaas -[kwilczynski: commit log] -Signed-off-by: Krzysztof Wilczyński ---- - drivers/pci/pcie/aspm.c | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - -diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c -index cf4acea6610d..20ec2a4aae65 100644 ---- a/drivers/pci/pcie/aspm.c -+++ b/drivers/pci/pcie/aspm.c -@@ -1031,16 +1031,16 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) - parent_link = link->parent; - - /* -- * link->downstream is a pointer to the pci_dev of function 0. If -- * we remove that function, the pci_dev is about to be deallocated, -- * so we can't use link->downstream again. Free the link state to -- * avoid this. -+ * Free the parent link state, no later than function 0 (i.e. -+ * link->downstream) being removed. - * -- * If we're removing a non-0 function, it's possible we could -- * retain the link state, but PCIe r6.0, sec 7.5.3.7, recommends -- * programming the same ASPM Control value for all functions of -- * multi-function devices, so disable ASPM for all of them. -+ * Do not free the link state any earlier. If function 0 is a -+ * switch upstream port, this link state is parent_link to all -+ * subordinate ones. - */ -+ if (pdev != link->downstream) -+ goto out; -+ - pcie_config_aspm_link(link, 0); - list_del(&link->sibling); - free_link_state(link); -@@ -1051,6 +1051,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) - pcie_config_aspm_path(parent_link); - } - -+ out: - mutex_unlock(&aspm_lock); - up_read(&pci_bus_sem); - } diff --git a/patches-sonic/arista_goldfinch-dts.patch b/patches-sonic/arista_goldfinch-dts.patch index f7dce73e1..63093226a 100644 --- a/patches-sonic/arista_goldfinch-dts.patch +++ b/patches-sonic/arista_goldfinch-dts.patch @@ -24,9 +24,9 @@ index 5caf80a7f..496ae839d 100644 nexthop-b27-r0.dtb \ nokia-ast2700-h6-128-r0.dtb \ + arista_goldfinch-r0.dtb \ + ast2700-evb_ast1700-evb.dtb \ + ast2700-evb_ast1700-evb-dual.dtb \ ast2700-raw.dtb \ - ast2700-evb-s0.dtb \ - ast2700-evb-s1.dtb \ diff --git a/arch/arm64/boot/dts/aspeed/arista_goldfinch-r0.dts b/arch/arm64/boot/dts/aspeed/arista_goldfinch-r0.dts new file mode 100644 index 000000000..52536fc16 diff --git a/patches-sonic/aspeed-spi-txrx-fix-full-duplex-capture.patch b/patches-sonic/aspeed-spi-txrx-fix-full-duplex-capture.patch index af8d5d07b..f75c364cf 100644 --- a/patches-sonic/aspeed-spi-txrx-fix-full-duplex-capture.patch +++ b/patches-sonic/aspeed-spi-txrx-fix-full-duplex-capture.patch @@ -43,5 +43,5 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c - if (rx_buf && rx_buf != tx_buf) { + if (rx_buf && !tx_buf) { ctrl_val &= ~SPI_IO_MASK; - if (spi->mode & SPI_RX_DUAL) + if (xfer->rx_nbits == SPI_NBITS_DUAL) ctrl_val |= SPI_DUAL_IO_MODE; diff --git a/patches-sonic/cisco-hwmon-pmbus_core-pec-support-check.patch b/patches-sonic/cisco-hwmon-pmbus_core-pec-support-check.patch deleted file mode 100644 index bd6d5cedd..000000000 --- a/patches-sonic/cisco-hwmon-pmbus_core-pec-support-check.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 8451736f488d2e24da57a6d6d8a3880bd023812b Mon Sep 17 00:00:00 2001 -From: Madhava Reddy Siddareddygari -Date: Tue, 9 Nov 2021 10:54:31 -0800 -Subject: [PATCH] hwmon: (pmbus_core) Check adapter PEC support - -Currently, for Packet Error Checking (PEC) only the controller -is checked for support. This causes problems on the cisco-8000 -platform where a SMBUS transaction errors are observed. This is -because PEC has to be enabled only if both controller and -adapter supports it. - -Added code to check PEC capability for adapter and enable it -only if both controller and adapter supports PEC. - -This patch was applied to Linux 5.14 in commit -4e5418f787ec56d7fe3c6efee486b8f508c58baf -(hwmon: (pmbus_core) Check adapter PEC support). - -Signed-off-by: Madhava Reddy Siddareddygari ---- - drivers/hwmon/pmbus/pmbus_core.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c -index 192442b3b..634615324 100644 ---- a/drivers/hwmon/pmbus/pmbus_core.c -+++ b/drivers/hwmon/pmbus/pmbus_core.c -@@ -2203,10 +2203,12 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, - data->has_status_word = true; - } - -- /* Enable PEC if the controller supports it */ -- ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); -- if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) -- client->flags |= I2C_CLIENT_PEC; -+ /* Enable PEC if the controller and bus support it */ -+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) { -+ ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); -+ if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) -+ client->flags |= I2C_CLIENT_PEC; -+ } - - /* - * Check if the chip is write protected. If it is, we can not clear --- -2.25.1 - diff --git a/patches-sonic/cisco-x86-gpio-config.patch b/patches-sonic/cisco-x86-gpio-config.patch deleted file mode 100644 index 5df46b7b1..000000000 --- a/patches-sonic/cisco-x86-gpio-config.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7106f3961be1dc0d921efe5c719ada6096307227 Mon Sep 17 00:00:00 2001 -From: Madhava Reddy Siddareddygari -Date: Tue, 10 Aug 2021 12:51:47 -0700 -Subject: [PATCH] x86/Kconfig: Introduce ARCH_NR_GPIO - -The x86 platform did not allow configuring the maximum number of GPIOs -supported, although the ARM platform did. For cisco-8000 platform, -each FPGA gpio IP block can support 1K pins. Distributed chassis with -Route Processor and Fabric cards can have 10 such IP blocks, along with -additional pins through i2c gpio extenders. - -This patch supports configurable number of GPIO's at kernel config time -similar to ARM platform. - -Signed-off-by: Madhava Reddy Siddareddygari ---- - arch/x86/Kconfig | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index d2453b251..e894cd71d 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -342,6 +342,11 @@ config SCHED_MC_PRIO - - config ARCH_NR_GPIO - int -+ prompt "Maximum number of GPIO's" - default 1024 if X86_64 - default 512 -+ help -+ Maximum number of GPIOs in the system. -+ -+ If unsure, leave the default value. - - config ARCH_SUSPEND_POSSIBLE - def_bool y --- -2.26.2 - diff --git a/patches-sonic/driver-arista-pci-clear-aer-error-on-recovery-failure.patch b/patches-sonic/driver-arista-pci-clear-aer-error-on-recovery-failure.patch index 095beeac0..750506cdd 100644 --- a/patches-sonic/driver-arista-pci-clear-aer-error-on-recovery-failure.patch +++ b/patches-sonic/driver-arista-pci-clear-aer-error-on-recovery-failure.patch @@ -135,6 +135,6 @@ index bb5ec0c..898d4d4 100644 + pci_walk_bridge(bridge, pci_pm_runtime_put, NULL); - pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT); + pci_walk_bridge(bridge, report_perm_failure_detected, NULL); -- 2.51.0 diff --git a/patches-sonic/mmc-sdhci-of-aspeed-Improve-CMD6-timing_v6.18.patch b/patches-sonic/mmc-sdhci-of-aspeed-Improve-CMD6-timing_v6.18.patch deleted file mode 100644 index 4a32648e4..000000000 --- a/patches-sonic/mmc-sdhci-of-aspeed-Improve-CMD6-timing_v6.18.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 5f1adff1a89dd68acfe81157b9c20b38d87ba18f Mon Sep 17 00:00:00 2001 -From: Cool Lee -Date: Fri, 10 Apr 2026 15:37:51 +0800 -Subject: [PATCH] mmc: sdhci-of-aspeed: Improve CMD6 timing - -The timing is critical before select_hs200 due to a 1_8V_SIGNAL is set. -When this is set, the post edge between CLK and CMD is tight. Make an -inverse to get a tolerance before CMD6 to switch HS200. - -Signed-off-by: Cool Lee -(cherry picked from commit e3532140fbe86fe88abacde37aebbbd5520fbc9d) -Upstream: https://github.com/AspeedTech-BMC/linux/commit/e3532140fbe86fe88abacde37aebbbd5520fbc9d -Signed-off-by: Prajjwal Singh ---- - drivers/mmc/host/sdhci-of-aspeed.c | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c -index 6d309f47d..e4a1e91c5 100644 ---- a/drivers/mmc/host/sdhci-of-aspeed.c -+++ b/drivers/mmc/host/sdhci-of-aspeed.c -@@ -312,6 +312,24 @@ static int aspeed_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) - - static void aspeed_sdhci_voltage_switch(struct sdhci_host *host) - { -+ struct sdhci_pltfm_host *pltfm_priv; -+ struct aspeed_sdhci *sdhci; -+ struct aspeed_sdc *sdc; -+ u32 out_phase, enable_mask, inverted = 1; -+ -+ pltfm_priv = sdhci_priv(host); -+ sdhci = sdhci_pltfm_priv(pltfm_priv); -+ sdc = sdhci->parent; -+ -+ enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN | ASPEED_SDC_S0_PHASE_IN_EN; -+ -+ inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; -+ out_phase = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; -+ out_phase |= (inverted << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -+ -+ /* output inverse */ -+ writel(out_phase | enable_mask, sdc->regs + ASPEED_SDC_PHASE); -+ - mdelay(30); - } - --- -2.47.3 - diff --git a/patches-sonic/mmc-sdhci-of-aspeed-Optimize-tuning-mechanism_v6.12.patch b/patches-sonic/mmc-sdhci-of-aspeed-Optimize-tuning-mechanism_v6.12.patch deleted file mode 100644 index 0ed7da118..000000000 --- a/patches-sonic/mmc-sdhci-of-aspeed-Optimize-tuning-mechanism_v6.12.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 2af0060637db659bd20798de0e0896ce0b0fa1e6 Mon Sep 17 00:00:00 2001 -From: Cool Lee -Date: Fri, 24 Apr 2026 10:43:49 +0800 -Subject: [PATCH] mmc: sdhci-of-aspeed: Optimize tuning mechanism - -Rewrote aspeed_sdhci_execute_tuning with circular window detection -across all 30 phase positions. - -Signed-off-by: Cool Lee -(cherry picked from commit 5fa88b13a96cf0059009f13cdf0b5b8b7b9c51ea) -Upstream: https://github.com/AspeedTech-BMC/linux/commit/5fa88b13a96cf0059009f13cdf0b5b8b7b9c51ea -Signed-off-by: Prajjwal Singh ---- - drivers/mmc/host/sdhci-of-aspeed.c | 178 ++++++++++++++++------------- - 1 file changed, 96 insertions(+), 82 deletions(-) - -diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c -index e4a1e91c5..684301b5d 100644 ---- a/drivers/mmc/host/sdhci-of-aspeed.c -+++ b/drivers/mmc/host/sdhci-of-aspeed.c -@@ -201,111 +201,125 @@ static void aspeed_sdhci_reset(struct sdhci_host *host, u8 mask) - sdhci_reset(host, mask); - } - -+/* -+ * aspeed_sdhci_find_center_tap - find the midpoint of the widest passing window -+ * @pass: boolean array [0..total-1], true = tuning passed at this position -+ * @total: number of phase positions (ASPEED_SDHCI_NR_TAPS * 2 = 30) -+ * -+ * Phase space layout (15 taps = half cycle at 200 MHz, ~167 ps/tap): -+ * pos [0..14] - rising edge, tap delay 0..14 ( 0° .. ~168°) -+ * pos [15..29] - falling edge, tap delay 0..14 (180° .. ~348°) -+ * -+ * The array is treated as circular so windows that wrap across the -+ * rising/falling boundary (around 0°/360°) are detected correctly. -+ * -+ * Returns a 5-bit phase_bits value: -+ * bits [3:0] = tap index -+ * bit [4] = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK (set for falling edge) -+ */ -+static u32 aspeed_sdhci_find_center_tap(const bool *pass, int total) -+{ -+ int pos, cur_start = -1, cur_len = 0, best_start = 0, best_len = 0; -+ int center_pos; -+ -+ /* -+ * Double-scan the circular buffer: the second pass detects windows -+ * that straddle the index-0 wrap-around boundary. The window length -+ * is capped at 'total' so a full-circle window is counted only once. -+ */ -+ for (pos = 0; pos < total * 2; pos++) { -+ if (pass[pos % total]) { -+ if (cur_start < 0) -+ cur_start = pos; -+ if (++cur_len > total) -+ cur_len = total; -+ if (cur_len > best_len) { -+ best_len = cur_len; -+ best_start = cur_start; -+ } -+ } else { -+ cur_start = -1; -+ cur_len = 0; -+ } -+ } -+ -+ if (!best_len) -+ return 0; -+ -+ center_pos = (best_start + best_len / 2) % total; -+ -+ if (center_pos < ASPEED_SDHCI_NR_TAPS) -+ return (u32)center_pos; -+ -+ return (u32)(center_pos - ASPEED_SDHCI_NR_TAPS) | ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; -+} -+ - static int aspeed_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) - { - struct sdhci_pltfm_host *pltfm_priv; - struct aspeed_sdhci *sdhci; - struct aspeed_sdc *sdc; - struct device *dev; -- -- u32 val, left, right, edge; -- u32 window, oldwindow = 0, center; -- u32 in_phase, out_phase, enable_mask, inverted = 0; -+ /* -+ * 15 taps cover half a 200 MHz clock cycle (2.5 ns ≈ 167 ps/tap). -+ * Rising and falling edges together span a full cycle: 30 positions. -+ */ -+ const int total = ASPEED_SDHCI_NR_TAPS * 2; -+ bool pass[ASPEED_SDHCI_NR_TAPS * 2]; -+ u32 enable_mask, base, val, phase_bits; -+ int pos; - - dev = mmc_dev(host->mmc); - pltfm_priv = sdhci_priv(host); - sdhci = sdhci_pltfm_priv(pltfm_priv); - sdc = sdhci->parent; - -- out_phase = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; -- - enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN | ASPEED_SDC_S0_PHASE_IN_EN; -- -- /* -- * There are two window upon clock rising and falling edge. -- * Iterate each tap delay to find the valid window and choose the -- * bigger one, set the tap delay at the middle of window. -- */ -- for (edge = 0; edge < 2; edge++) { -- if (edge == 1) -- inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; -- -- val = (out_phase | enable_mask | (inverted << ASPEED_SDC_S0_PHASE_IN_SHIFT)); -- -- /* find the left boundary */ -- for (left = 0; left < ASPEED_SDHCI_NR_TAPS + 1; left++) { -- in_phase = val | (left << ASPEED_SDC_S0_PHASE_IN_SHIFT); -- writel(in_phase, sdc->regs + ASPEED_SDC_PHASE); -- -- if (!mmc_send_tuning(host->mmc, opcode, NULL)) -- break; -- } -- -- /* find the right boundary */ -- for (right = left + 1; right < ASPEED_SDHCI_NR_TAPS + 1; right++) { -- in_phase = val | (right << ASPEED_SDC_S0_PHASE_IN_SHIFT); -- writel(in_phase, sdc->regs + ASPEED_SDC_PHASE); -- -- if (mmc_send_tuning(host->mmc, opcode, NULL)) -- break; -- } -- -- window = right - left; -- pr_debug("tuning window[%d][%d~%d] = %d\n", edge, left, right, window); -- -- if (window > oldwindow) { -- oldwindow = window; -- center = (((right - 1) + left) / 2) | inverted; -- } -+ base = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; -+ -+ /* -------- Step 1: scan all input-phase positions -------- */ -+ for (pos = 0; pos < total; pos++) { -+ phase_bits = (pos < ASPEED_SDHCI_NR_TAPS) -+ ? (u32)pos -+ : (u32)(pos - ASPEED_SDHCI_NR_TAPS) | ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; -+ -+ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_IN_SHIFT); -+ writel(val, sdc->regs + ASPEED_SDC_PHASE); -+ pass[pos] = !mmc_send_tuning(host->mmc, opcode, NULL); -+ -+ dev_dbg(dev, "in pos=%2d (%s tap%2u) %s\n", pos, -+ pos < ASPEED_SDHCI_NR_TAPS ? "rise" : "fall", -+ pos % ASPEED_SDHCI_NR_TAPS, -+ pass[pos] ? "pass" : "fail"); - } - -- val = (out_phase | enable_mask | (center << ASPEED_SDC_S0_PHASE_IN_SHIFT)); -+ phase_bits = aspeed_sdhci_find_center_tap(pass, total); -+ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_IN_SHIFT); - writel(val, sdc->regs + ASPEED_SDC_PHASE); -+ dev_dbg(dev, "input center: phase_bits=0x%02x reg=0x%08x\n", phase_bits, val); - -- pr_debug("input tuning result=%x\n", val); -- -- inverted = 0; -- out_phase = val & ~ASPEED_SDC_S0_PHASE_OUT; -- in_phase = out_phase; -- oldwindow = 0; -- -- for (edge = 0; edge < 2; edge++) { -- if (edge == 1) -- inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; -+ /* -------- Step 2: scan all output-phase positions -------- */ -+ base = val & ~ASPEED_SDC_S0_PHASE_OUT; - -- val = (in_phase | enable_mask | (inverted << ASPEED_SDC_S0_PHASE_OUT_SHIFT)); -- -- /* find the left boundary */ -- for (left = 0; left < ASPEED_SDHCI_NR_TAPS + 1; left++) { -- out_phase = val | (left << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -- writel(out_phase, sdc->regs + ASPEED_SDC_PHASE); -- -- if (!mmc_send_tuning(host->mmc, opcode, NULL)) -- break; -- } -+ for (pos = 0; pos < total; pos++) { -+ phase_bits = (pos < ASPEED_SDHCI_NR_TAPS) -+ ? (u32)pos -+ : (u32)(pos - ASPEED_SDHCI_NR_TAPS) | ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; - -- /* find the right boundary */ -- for (right = left + 1; right < ASPEED_SDHCI_NR_TAPS + 1; right++) { -- out_phase = val | (right << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -- writel(out_phase, sdc->regs + ASPEED_SDC_PHASE); -+ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_OUT_SHIFT); -+ writel(val, sdc->regs + ASPEED_SDC_PHASE); -+ pass[pos] = !mmc_send_tuning(host->mmc, opcode, NULL); - -- if (mmc_send_tuning(host->mmc, opcode, NULL)) -- break; -- } -- -- window = right - left; -- pr_debug("tuning window[%d][%d~%d] = %d\n", edge, left, right, window); -- -- if (window > oldwindow) { -- oldwindow = window; -- center = (((right - 1) + left) / 2) | inverted; -- } -+ dev_dbg(dev, "out pos=%2d (%s tap%2u) %s\n", pos, -+ pos < ASPEED_SDHCI_NR_TAPS ? "rise" : "fall", -+ pos % ASPEED_SDHCI_NR_TAPS, -+ pass[pos] ? "pass" : "fail"); - } - -- val = (in_phase | enable_mask | (center << ASPEED_SDC_S0_PHASE_OUT_SHIFT)); -+ phase_bits = aspeed_sdhci_find_center_tap(pass, total); -+ val = base | enable_mask | (phase_bits << ASPEED_SDC_S0_PHASE_OUT_SHIFT); - writel(val, sdc->regs + ASPEED_SDC_PHASE); -- -- pr_debug("output tuning result=%x\n", val); -+ dev_dbg(dev, "output center: phase_bits=0x%02x reg=0x%08x\n", phase_bits, val); - - return mmc_send_tuning(host->mmc, opcode, NULL); - } --- -2.47.3 - diff --git a/patches-sonic/nexthop-b27-dts.patch b/patches-sonic/nexthop-b27-dts.patch index b315f8b5c..4ccce2685 100644 --- a/patches-sonic/nexthop-b27-dts.patch +++ b/patches-sonic/nexthop-b27-dts.patch @@ -29,9 +29,9 @@ index 7c31f31..3e904b2 100644 dtb-$(CONFIG_ARCH_ASPEED) += \ ast2700-evb.dtb \ + nexthop-b27-r0.dtb \ + ast2700-evb_ast1700-evb.dtb \ + ast2700-evb_ast1700-evb-dual.dtb \ ast2700-raw.dtb \ - ast2700-evb-s0.dtb \ - ast2700-evb-s1.dtb \ diff --git a/arch/arm64/boot/dts/aspeed/nexthop-b27-r0.dts b/arch/arm64/boot/dts/aspeed/nexthop-b27-r0.dts new file mode 100644 index 0000000..7d1f339 diff --git a/patches-sonic/qsa-2026-apparmor/0001-apparmor-validate-DFA-start-states-are-in-bounds-in-.patch b/patches-sonic/qsa-2026-apparmor/0001-apparmor-validate-DFA-start-states-are-in-bounds-in-.patch deleted file mode 100644 index 3447056fa..000000000 --- a/patches-sonic/qsa-2026-apparmor/0001-apparmor-validate-DFA-start-states-are-in-bounds-in-.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0bc5b34e913eadcd3bcc51e4d365bf35f81b5c1f Mon Sep 17 00:00:00 2001 -From: Massimiliano Pellizzer -Date: Thu, 15 Jan 2026 15:30:50 +0100 -Subject: [PATCH 01/11] apparmor: validate DFA start states are in bounds in - unpack_pdb - -Start states are read from untrusted data and used as indexes into the -DFA state tables. The aa_dfa_next() function call in unpack_pdb() will -access dfa->tables[YYTD_ID_BASE][start], and if the start state exceeds -the number of states in the DFA, this results in an out-of-bound read. - -================================================================== - BUG: KASAN: slab-out-of-bounds in aa_dfa_next+0x2a1/0x360 - Read of size 4 at addr ffff88811956fb90 by task su/1097 - ... - -Reject policies with out-of-bounds start states during unpacking -to prevent the issue. - -Fixes: ad5ff3db53c6 ("AppArmor: Add ability to load extended policy") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: Massimiliano Pellizzer -Signed-off-by: John Johansen ---- - security/apparmor/policy_unpack.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c -index 3483c595f999..e472442274d1 100644 ---- a/security/apparmor/policy_unpack.c -+++ b/security/apparmor/policy_unpack.c -@@ -760,7 +760,17 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy, - if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], "dfa_start")) { - /* default start state for xmatch and file dfa */ - pdb->start[AA_CLASS_FILE] = DFA_START; -- } /* setup class index */ -+ } -+ -+ size_t state_count = pdb->dfa->tables[YYTD_ID_BASE]->td_lolen; -+ -+ if (pdb->start[0] >= state_count || -+ pdb->start[AA_CLASS_FILE] >= state_count) { -+ *info = "invalid dfa start state"; -+ goto fail; -+ } -+ -+ /* setup class index */ - for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) { - pdb->start[i] = aa_dfa_next(pdb->dfa, pdb->start[0], - i); --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0002-apparmor-fix-memory-leak-in-verify_header.patch b/patches-sonic/qsa-2026-apparmor/0002-apparmor-fix-memory-leak-in-verify_header.patch deleted file mode 100644 index a7986efbc..000000000 --- a/patches-sonic/qsa-2026-apparmor/0002-apparmor-fix-memory-leak-in-verify_header.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 66ecb6689b1ee73fd2ecf7aea226ef21d72163cd Mon Sep 17 00:00:00 2001 -From: Massimiliano Pellizzer -Date: Tue, 20 Jan 2026 15:24:04 +0100 -Subject: [PATCH 02/11] apparmor: fix memory leak in verify_header - -The function sets `*ns = NULL` on every call, leaking the namespace -string allocated in previous iterations when multiple profiles are -unpacked. This also breaks namespace consistency checking since *ns -is always NULL when the comparison is made. - -Remove the incorrect assignment. -The caller (aa_unpack) initializes *ns to NULL once before the loop, -which is sufficient. - -Fixes: dd51c8485763 ("apparmor: provide base for multiple profiles to be replaced at once") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: Massimiliano Pellizzer -Signed-off-by: John Johansen ---- - security/apparmor/policy_unpack.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c -index e472442274d1..0232fc29a234 100644 ---- a/security/apparmor/policy_unpack.c -+++ b/security/apparmor/policy_unpack.c -@@ -1140,7 +1140,6 @@ static int verify_header(struct aa_ext *e, int required, const char **ns) - { - int error = -EPROTONOSUPPORT; - const char *name = NULL; -- *ns = NULL; - - /* get the interface version */ - if (!aa_unpack_u32(e, &e->version, "version")) { --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0003-apparmor-replace-recursive-profile-removal-with-iter.patch b/patches-sonic/qsa-2026-apparmor/0003-apparmor-replace-recursive-profile-removal-with-iter.patch deleted file mode 100644 index 26a038e22..000000000 --- a/patches-sonic/qsa-2026-apparmor/0003-apparmor-replace-recursive-profile-removal-with-iter.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 83417f15ea8253d96e6636fbb1c1cf95c0e6b6af Mon Sep 17 00:00:00 2001 -From: Massimiliano Pellizzer -Date: Tue, 13 Jan 2026 09:09:43 +0100 -Subject: [PATCH 03/11] apparmor: replace recursive profile removal with - iterative approach - -The profile removal code uses recursion when removing nested profiles, -which can lead to kernel stack exhaustion and system crashes. - -Reproducer: - $ pf='a'; for ((i=0; i<1024; i++)); do - echo -e "profile $pf { \n }" | apparmor_parser -K -a; - pf="$pf//x"; - done - $ echo -n a > /sys/kernel/security/apparmor/.remove - -Replace the recursive __aa_profile_list_release() approach with an -iterative approach in __remove_profile(). The function repeatedly -finds and removes leaf profiles until the entire subtree is removed, -maintaining the same removal semantic without recursion. - -Fixes: c88d4c7b049e ("AppArmor: core policy routines") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: Massimiliano Pellizzer -Signed-off-by: John Johansen ---- - security/apparmor/policy.c | 30 +++++++++++++++++++++++++++--- - 1 file changed, 27 insertions(+), 3 deletions(-) - -diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c -index 105706abf281..f6869ea00d1d 100644 ---- a/security/apparmor/policy.c -+++ b/security/apparmor/policy.c -@@ -184,19 +184,43 @@ static void __list_remove_profile(struct aa_profile *profile) - } - - /** -- * __remove_profile - remove old profile, and children -- * @profile: profile to be replaced (NOT NULL) -+ * __remove_profile - remove profile, and children -+ * @profile: profile to be removed (NOT NULL) - * - * Requires: namespace list lock be held, or list not be shared - */ - static void __remove_profile(struct aa_profile *profile) - { -+ struct aa_profile *curr, *to_remove; -+ - AA_BUG(!profile); - AA_BUG(!profile->ns); - AA_BUG(!mutex_is_locked(&profile->ns->lock)); - - /* release any children lists first */ -- __aa_profile_list_release(&profile->base.profiles); -+ if (!list_empty(&profile->base.profiles)) { -+ curr = list_first_entry(&profile->base.profiles, struct aa_profile, base.list); -+ -+ while (curr != profile) { -+ -+ while (!list_empty(&curr->base.profiles)) -+ curr = list_first_entry(&curr->base.profiles, -+ struct aa_profile, base.list); -+ -+ to_remove = curr; -+ if (!list_is_last(&to_remove->base.list, -+ &aa_deref_parent(curr)->base.profiles)) -+ curr = list_next_entry(to_remove, base.list); -+ else -+ curr = aa_deref_parent(curr); -+ -+ /* released by free_profile */ -+ aa_label_remove(&to_remove->label); -+ __aafs_profile_rmdir(to_remove); -+ __list_remove_profile(to_remove); -+ } -+ } -+ - /* released by free_profile */ - aa_label_remove(&profile->label); - __aafs_profile_rmdir(profile); --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0004-apparmor-fix-limit-the-number-of-levels-of-policy-na.patch b/patches-sonic/qsa-2026-apparmor/0004-apparmor-fix-limit-the-number-of-levels-of-policy-na.patch deleted file mode 100644 index a506aa58f..000000000 --- a/patches-sonic/qsa-2026-apparmor/0004-apparmor-fix-limit-the-number-of-levels-of-policy-na.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 4fd74536d8c7e2fc69dc58907a2b082e393cfff4 Mon Sep 17 00:00:00 2001 -From: John Johansen -Date: Tue, 3 Mar 2026 11:08:02 -0800 -Subject: [PATCH 04/11] apparmor: fix: limit the number of levels of policy - namespaces - -Currently the number of policy namespaces is not bounded relying on -the user namespace limit. However policy namespaces aren't strictly -tied to user namespaces and it is possible to create them and nest -them arbitrarily deep which can be used to exhaust system resource. - -Hard cap policy namespaces to the same depth as user namespaces. - -Fixes: c88d4c7b049e8 ("AppArmor: core policy routines") -Reported-by: Qualys Security Advisory -Reviewed-by: Ryan Lee -Reviewed-by: Cengiz Can -Signed-off-by: John Johansen ---- - security/apparmor/include/policy_ns.h | 2 ++ - security/apparmor/policy_ns.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h -index d646070fd966..cc6e84151812 100644 ---- a/security/apparmor/include/policy_ns.h -+++ b/security/apparmor/include/policy_ns.h -@@ -18,6 +18,8 @@ - #include "label.h" - #include "policy.h" - -+/* Match max depth of user namespaces */ -+#define MAX_NS_DEPTH 32 - - /* struct aa_ns_acct - accounting of profiles in namespace - * @max_size: maximum space allowed for all profiles in namespace -diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c -index 1f02cfe1d974..06c0bde97a63 100644 ---- a/security/apparmor/policy_ns.c -+++ b/security/apparmor/policy_ns.c -@@ -223,6 +223,8 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, - AA_BUG(!name); - AA_BUG(!mutex_is_locked(&parent->lock)); - -+ if (parent->level > MAX_NS_DEPTH) -+ return ERR_PTR(-ENOSPC); - ns = alloc_ns(parent->base.hname, name); - if (!ns) - return ERR_PTR(-ENOMEM); --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0005-apparmor-fix-side-effect-bug-in-match_char-macro-usa.patch b/patches-sonic/qsa-2026-apparmor/0005-apparmor-fix-side-effect-bug-in-match_char-macro-usa.patch deleted file mode 100644 index df6b18709..000000000 --- a/patches-sonic/qsa-2026-apparmor/0005-apparmor-fix-side-effect-bug-in-match_char-macro-usa.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 05302d7b0886b14de3d0e91a1b0c332f9ea0d292 Mon Sep 17 00:00:00 2001 -From: Massimiliano Pellizzer -Date: Thu, 29 Jan 2026 17:08:25 +0100 -Subject: [PATCH 05/11] apparmor: fix side-effect bug in match_char() macro - usage - -The match_char() macro evaluates its character parameter multiple -times when traversing differential encoding chains. When invoked -with *str++, the string pointer advances on each iteration of the -inner do-while loop, causing the DFA to check different characters -at each iteration and therefore skip input characters. -This results in out-of-bounds reads when the pointer advances past -the input buffer boundary. - -[ 94.984676] ================================================================== -[ 94.985301] BUG: KASAN: slab-out-of-bounds in aa_dfa_match+0x5ae/0x760 -[ 94.985655] Read of size 1 at addr ffff888100342000 by task file/976 - -[ 94.986319] CPU: 7 UID: 1000 PID: 976 Comm: file Not tainted 6.19.0-rc7-next-20260127 #1 PREEMPT(lazy) -[ 94.986322] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 -[ 94.986329] Call Trace: -[ 94.986341] -[ 94.986347] dump_stack_lvl+0x5e/0x80 -[ 94.986374] print_report+0xc8/0x270 -[ 94.986384] ? aa_dfa_match+0x5ae/0x760 -[ 94.986388] kasan_report+0x118/0x150 -[ 94.986401] ? aa_dfa_match+0x5ae/0x760 -[ 94.986405] aa_dfa_match+0x5ae/0x760 -[ 94.986408] __aa_path_perm+0x131/0x400 -[ 94.986418] aa_path_perm+0x219/0x2f0 -[ 94.986424] apparmor_file_open+0x345/0x570 -[ 94.986431] security_file_open+0x5c/0x140 -[ 94.986442] do_dentry_open+0x2f6/0x1120 -[ 94.986450] vfs_open+0x38/0x2b0 -[ 94.986453] ? may_open+0x1e2/0x2b0 -[ 94.986466] path_openat+0x231b/0x2b30 -[ 94.986469] ? __x64_sys_openat+0xf8/0x130 -[ 94.986477] do_file_open+0x19d/0x360 -[ 94.986487] do_sys_openat2+0x98/0x100 -[ 94.986491] __x64_sys_openat+0xf8/0x130 -[ 94.986499] do_syscall_64+0x8e/0x660 -[ 94.986515] ? count_memcg_events+0x15f/0x3c0 -[ 94.986526] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 94.986540] ? handle_mm_fault+0x1639/0x1ef0 -[ 94.986551] ? vma_start_read+0xf0/0x320 -[ 94.986558] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 94.986561] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 94.986563] ? fpregs_assert_state_consistent+0x50/0xe0 -[ 94.986572] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 94.986574] ? arch_exit_to_user_mode_prepare+0x9/0xb0 -[ 94.986587] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 94.986588] ? irqentry_exit+0x3c/0x590 -[ 94.986595] entry_SYSCALL_64_after_hwframe+0x76/0x7e -[ 94.986597] RIP: 0033:0x7fda4a79c3ea - -Fix by extracting the character value before invoking match_char, -ensuring single evaluation per outer loop. - -Fixes: 074c1cd798cb ("apparmor: dfa move character match into a macro") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: Massimiliano Pellizzer -Signed-off-by: John Johansen ---- - security/apparmor/match.c | 30 ++++++++++++++++++++---------- - 1 file changed, 20 insertions(+), 10 deletions(-) - -diff --git a/security/apparmor/match.c b/security/apparmor/match.c -index 12e036f8ce0f..5fbfdd75afb5 100644 ---- a/security/apparmor/match.c -+++ b/security/apparmor/match.c -@@ -408,13 +408,18 @@ aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, - if (dfa->tables[YYTD_ID_EC]) { - /* Equivalence class table defined */ - u8 *equiv = EQUIV_TABLE(dfa); -- for (; len; len--) -- match_char(state, def, base, next, check, -- equiv[(u8) *str++]); -+ for (; len; len--) { -+ u8 c = equiv[(u8) *str]; -+ -+ match_char(state, def, base, next, check, c); -+ str++; -+ } - } else { - /* default is direct to next state */ -- for (; len; len--) -- match_char(state, def, base, next, check, (u8) *str++); -+ for (; len; len--) { -+ match_char(state, def, base, next, check, (u8) *str); -+ str++; -+ } - } - - return state; -@@ -448,13 +453,18 @@ aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str) - /* Equivalence class table defined */ - u8 *equiv = EQUIV_TABLE(dfa); - /* default is direct to next state */ -- while (*str) -- match_char(state, def, base, next, check, -- equiv[(u8) *str++]); -+ while (*str) { -+ u8 c = equiv[(u8) *str]; -+ -+ match_char(state, def, base, next, check, c); -+ str++; -+ } - } else { - /* default is direct to next state */ -- while (*str) -- match_char(state, def, base, next, check, (u8) *str++); -+ while (*str) { -+ match_char(state, def, base, next, check, (u8) *str); -+ str++; -+ } - } - - return state; --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0006-apparmor-fix-missing-bounds-check-on-DEFAULT-table-i.patch b/patches-sonic/qsa-2026-apparmor/0006-apparmor-fix-missing-bounds-check-on-DEFAULT-table-i.patch deleted file mode 100644 index 9ba69881d..000000000 --- a/patches-sonic/qsa-2026-apparmor/0006-apparmor-fix-missing-bounds-check-on-DEFAULT-table-i.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 32ef9e21844645607f4d24203cede23e1a76ceec Mon Sep 17 00:00:00 2001 -From: Massimiliano Pellizzer -Date: Thu, 29 Jan 2026 16:51:11 +0100 -Subject: [PATCH 06/11] apparmor: fix missing bounds check on DEFAULT table in - verify_dfa() - -The verify_dfa() function only checks DEFAULT_TABLE bounds when the state -is not differentially encoded. - -When the verification loop traverses the differential encoding chain, -it reads k = DEFAULT_TABLE[j] and uses k as an array index without -validation. A malformed DFA with DEFAULT_TABLE[j] >= state_count, -therefore, causes both out-of-bounds reads and writes. - -[ 57.179855] ================================================================== -[ 57.180549] BUG: KASAN: slab-out-of-bounds in verify_dfa+0x59a/0x660 -[ 57.180904] Read of size 4 at addr ffff888100eadec4 by task su/993 - -[ 57.181554] CPU: 1 UID: 0 PID: 993 Comm: su Not tainted 6.19.0-rc7-next-20260127 #1 PREEMPT(lazy) -[ 57.181558] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 -[ 57.181563] Call Trace: -[ 57.181572] -[ 57.181577] dump_stack_lvl+0x5e/0x80 -[ 57.181596] print_report+0xc8/0x270 -[ 57.181605] ? verify_dfa+0x59a/0x660 -[ 57.181608] kasan_report+0x118/0x150 -[ 57.181620] ? verify_dfa+0x59a/0x660 -[ 57.181623] verify_dfa+0x59a/0x660 -[ 57.181627] aa_dfa_unpack+0x1610/0x1740 -[ 57.181629] ? __kmalloc_cache_noprof+0x1d0/0x470 -[ 57.181640] unpack_pdb+0x86d/0x46b0 -[ 57.181647] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 57.181653] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 57.181656] ? aa_unpack_nameX+0x1a8/0x300 -[ 57.181659] aa_unpack+0x20b0/0x4c30 -[ 57.181662] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 57.181664] ? stack_depot_save_flags+0x33/0x700 -[ 57.181681] ? kasan_save_track+0x4f/0x80 -[ 57.181683] ? kasan_save_track+0x3e/0x80 -[ 57.181686] ? __kasan_kmalloc+0x93/0xb0 -[ 57.181688] ? __kvmalloc_node_noprof+0x44a/0x780 -[ 57.181693] ? aa_simple_write_to_buffer+0x54/0x130 -[ 57.181697] ? policy_update+0x154/0x330 -[ 57.181704] aa_replace_profiles+0x15a/0x1dd0 -[ 57.181707] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 57.181710] ? __kvmalloc_node_noprof+0x44a/0x780 -[ 57.181712] ? aa_loaddata_alloc+0x77/0x140 -[ 57.181715] ? srso_alias_return_thunk+0x5/0xfbef5 -[ 57.181717] ? _copy_from_user+0x2a/0x70 -[ 57.181730] policy_update+0x17a/0x330 -[ 57.181733] profile_replace+0x153/0x1a0 -[ 57.181735] ? rw_verify_area+0x93/0x2d0 -[ 57.181740] vfs_write+0x235/0xab0 -[ 57.181745] ksys_write+0xb0/0x170 -[ 57.181748] do_syscall_64+0x8e/0x660 -[ 57.181762] entry_SYSCALL_64_after_hwframe+0x76/0x7e -[ 57.181765] RIP: 0033:0x7f6192792eb2 - -Remove the MATCH_FLAG_DIFF_ENCODE condition to validate all DEFAULT_TABLE -entries unconditionally. - -Fixes: 031dcc8f4e84 ("apparmor: dfa add support for state differential encoding") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: Massimiliano Pellizzer -Signed-off-by: John Johansen ---- - security/apparmor/match.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/security/apparmor/match.c b/security/apparmor/match.c -index 5fbfdd75afb5..98cf3b1f1649 100644 ---- a/security/apparmor/match.c -+++ b/security/apparmor/match.c -@@ -160,9 +160,10 @@ static int verify_dfa(struct aa_dfa *dfa) - if (state_count == 0) - goto out; - for (i = 0; i < state_count; i++) { -- if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && -- (DEFAULT_TABLE(dfa)[i] >= state_count)) -+ if (DEFAULT_TABLE(dfa)[i] >= state_count) { -+ pr_err("AppArmor DFA default state out of bounds"); - goto out; -+ } - if (BASE_TABLE(dfa)[i] & MATCH_FLAGS_INVALID) { - pr_err("AppArmor DFA state with invalid match flags"); - goto out; --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0007-apparmor-Fix-double-free-of-ns_name-in-aa_replace_pr.patch b/patches-sonic/qsa-2026-apparmor/0007-apparmor-Fix-double-free-of-ns_name-in-aa_replace_pr.patch deleted file mode 100644 index f87545d8b..000000000 --- a/patches-sonic/qsa-2026-apparmor/0007-apparmor-Fix-double-free-of-ns_name-in-aa_replace_pr.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 93eb370bd91e1f3f9eaa53a1a8fa910903febeed Mon Sep 17 00:00:00 2001 -From: John Johansen -Date: Wed, 10 Sep 2025 06:22:17 -0700 -Subject: [PATCH 07/11] apparmor: Fix double free of ns_name in - aa_replace_profiles() - -if ns_name is NULL after -1071 error = aa_unpack(udata, &lh, &ns_name); - -and if ent->ns_name contains an ns_name in -1089 } else if (ent->ns_name) { - -then ns_name is assigned the ent->ns_name -1095 ns_name = ent->ns_name; - -however ent->ns_name is freed at -1262 aa_load_ent_free(ent); - -and then again when freeing ns_name at -1270 kfree(ns_name); - -Fix this by NULLing out ent->ns_name after it is transferred to ns_name - -Fixes: 04dc715e24d08 ("apparmor: audit policy ns specified in policy load") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: John Johansen ---- - security/apparmor/policy.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c -index f6869ea00d1d..9a4e29cdd8c0 100644 ---- a/security/apparmor/policy.c -+++ b/security/apparmor/policy.c -@@ -1118,6 +1118,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, - goto fail; - } - ns_name = ent->ns_name; -+ ent->ns_name = NULL; - } else - count++; - } --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0008-apparmor-fix-unprivileged-local-user-can-do-privileg.patch b/patches-sonic/qsa-2026-apparmor/0008-apparmor-fix-unprivileged-local-user-can-do-privileg.patch deleted file mode 100644 index eb300c4ed..000000000 --- a/patches-sonic/qsa-2026-apparmor/0008-apparmor-fix-unprivileged-local-user-can-do-privileg.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 1e21c55c0b49ec1e88dd519f5d44695feb2adad9 Mon Sep 17 00:00:00 2001 -From: John Johansen -Date: Fri, 7 Nov 2025 08:36:04 -0800 -Subject: [PATCH 08/11] apparmor: fix unprivileged local user can do privileged - policy management - -An unprivileged local user can load, replace, and remove profiles by -opening the apparmorfs interfaces, via a confused deputy attack, by -passing the opened fd to a privileged process, and getting the -privileged process to write to the interface. - -This does require a privileged target that can be manipulated to do -the write for the unprivileged process, but once such access is -achieved full policy management is possible and all the possible -implications that implies: removing confinement, DoS of system or -target applications by denying all execution, by-passing the -unprivileged user namespace restriction, to exploiting kernel bugs for -a local privilege escalation. - -The policy management interface can not have its permissions simply -changed from 0666 to 0600 because non-root processes need to be able -to load policy to different policy namespaces. - -Instead ensure the task writing the interface has privileges that -are a subset of the task that opened the interface. This is already -done via policy for confined processes, but unconfined can delegate -access to the opened fd, by-passing the usual policy check. - -Fixes: c88d4c7b049e8 ("AppArmor: core policy routines") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: John Johansen ---- - security/apparmor/apparmorfs.c | 16 ++++++++------ - security/apparmor/include/policy.h | 2 +- - security/apparmor/policy.c | 34 +++++++++++++++++++++++++++++- - 3 files changed, 43 insertions(+), 9 deletions(-) - -diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c -index 01b923d97a44..c708f0bfe594 100644 ---- a/security/apparmor/apparmorfs.c -+++ b/security/apparmor/apparmorfs.c -@@ -412,7 +412,8 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, - } - - static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, -- loff_t *pos, struct aa_ns *ns) -+ loff_t *pos, struct aa_ns *ns, -+ const struct cred *ocred) - { - struct aa_loaddata *data; - struct aa_label *label; -@@ -423,7 +424,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, - /* high level check about policy management - fine grained in - * below after unpack - */ -- error = aa_may_manage_policy(current_cred(), label, ns, mask); -+ error = aa_may_manage_policy(current_cred(), label, ns, ocred, mask); - if (error) - goto end_section; - -@@ -444,7 +445,8 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, - loff_t *pos) - { - struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); -- int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns); -+ int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns, -+ f->f_cred); - - aa_put_ns(ns); - -@@ -462,7 +464,7 @@ static ssize_t profile_replace(struct file *f, const char __user *buf, - { - struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); - int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY, -- buf, size, pos, ns); -+ buf, size, pos, ns, f->f_cred); - aa_put_ns(ns); - - return error; -@@ -487,7 +489,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, - * below after unpack - */ - error = aa_may_manage_policy(current_cred(), label, ns, -- AA_MAY_REMOVE_POLICY); -+ f->f_cred, AA_MAY_REMOVE_POLICY); - if (error) - goto out; - -@@ -1804,7 +1806,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, - int error; - - label = begin_current_label_crit_section(); -- error = aa_may_manage_policy(current_cred(), label, NULL, -+ error = aa_may_manage_policy(current_cred(), label, NULL, NULL, - AA_MAY_LOAD_POLICY); - end_current_label_crit_section(label); - if (error) -@@ -1854,7 +1856,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) - int error; - - label = begin_current_label_crit_section(); -- error = aa_may_manage_policy(current_cred(), label, NULL, -+ error = aa_may_manage_policy(current_cred(), label, NULL, NULL, - AA_MAY_LOAD_POLICY); - end_current_label_crit_section(label); - if (error) -diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h -index 75088cc310b6..b8c35972883c 100644 ---- a/security/apparmor/include/policy.h -+++ b/security/apparmor/include/policy.h -@@ -393,7 +393,7 @@ bool aa_policy_admin_capable(const struct cred *subj_cred, - struct aa_label *label, struct aa_ns *ns); - int aa_may_manage_policy(const struct cred *subj_cred, - struct aa_label *label, struct aa_ns *ns, -- u32 mask); -+ const struct cred *ocred, u32 mask); - bool aa_current_policy_view_capable(struct aa_ns *ns); - bool aa_current_policy_admin_capable(struct aa_ns *ns); - -diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c -index 9a4e29cdd8c0..29f1cfd75090 100644 ---- a/security/apparmor/policy.c -+++ b/security/apparmor/policy.c -@@ -894,17 +894,44 @@ bool aa_current_policy_admin_capable(struct aa_ns *ns) - return res; - } - -+static bool is_subset_of_obj_privilege(const struct cred *cred, -+ struct aa_label *label, -+ const struct cred *ocred) -+{ -+ if (cred == ocred) -+ return true; -+ -+ if (!aa_label_is_subset(label, cred_label(ocred))) -+ return false; -+ /* don't allow crossing userns for now */ -+ if (cred->user_ns != ocred->user_ns) -+ return false; -+ if (!cap_issubset(cred->cap_inheritable, ocred->cap_inheritable)) -+ return false; -+ if (!cap_issubset(cred->cap_permitted, ocred->cap_permitted)) -+ return false; -+ if (!cap_issubset(cred->cap_effective, ocred->cap_effective)) -+ return false; -+ if (!cap_issubset(cred->cap_bset, ocred->cap_bset)) -+ return false; -+ if (!cap_issubset(cred->cap_ambient, ocred->cap_ambient)) -+ return false; -+ return true; -+} -+ -+ - /** - * aa_may_manage_policy - can the current task manage policy - * @subj_cred: subjects cred - * @label: label to check if it can manage policy - * @ns: namespace being managed by @label (may be NULL if @label's ns) -+ * @ocred: object cred if request is coming from an open object - * @mask: contains the policy manipulation operation being done - * - * Returns: 0 if the task is allowed to manipulate policy else error - */ - int aa_may_manage_policy(const struct cred *subj_cred, struct aa_label *label, -- struct aa_ns *ns, u32 mask) -+ struct aa_ns *ns, const struct cred *ocred, u32 mask) - { - const char *op; - -@@ -920,6 +947,11 @@ int aa_may_manage_policy(const struct cred *subj_cred, struct aa_label *label, - return audit_policy(label, op, NULL, NULL, "policy_locked", - -EACCES); - -+ if (ocred && !is_subset_of_obj_privilege(subj_cred, label, ocred)) -+ return audit_policy(label, op, NULL, NULL, -+ "not privileged for target profile", -+ -EACCES); -+ - if (!aa_policy_admin_capable(subj_cred, label, ns)) - return audit_policy(label, op, NULL, NULL, "not policy admin", - -EACCES); --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0009-apparmor-fix-differential-encoding-verification.patch b/patches-sonic/qsa-2026-apparmor/0009-apparmor-fix-differential-encoding-verification.patch deleted file mode 100644 index 9266e2bb6..000000000 --- a/patches-sonic/qsa-2026-apparmor/0009-apparmor-fix-differential-encoding-verification.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 4bf3bc43e05ddcf84032d415861308ac5c895732 Mon Sep 17 00:00:00 2001 -From: John Johansen -Date: Fri, 17 Oct 2025 01:53:00 -0700 -Subject: [PATCH 09/11] apparmor: fix differential encoding verification - -Differential encoding allows loops to be created if it is abused. To -prevent this the unpack should verify that a diff-encode chain -terminates. - -Unfortunately the differential encode verification had two bugs. - -1. it conflated states that had gone through check and already been - marked, with states that were currently being checked and marked. - This means that loops in the current chain being verified are treated - as a chain that has already been verified. - -2. the order bailout on already checked states compared current chain - check iterators j,k instead of using the outer loop iterator i. - Meaning a step backwards in states in the current chain verification - was being mistaken for moving to an already verified state. - -Move to a double mark scheme where already verified states get a -different mark, than the current chain being kept. This enables us -to also drop the backwards verification check that was the cause of -the second error as any already verified state is already marked. - -Fixes: 031dcc8f4e84 ("apparmor: dfa add support for state differential encoding") -Reported-by: Qualys Security Advisory -Tested-by: Salvatore Bonaccorso -Reviewed-by: Georgia Garcia -Reviewed-by: Cengiz Can -Signed-off-by: John Johansen ---- - security/apparmor/include/match.h | 1 + - security/apparmor/match.c | 23 +++++++++++++++++++---- - 2 files changed, 20 insertions(+), 4 deletions(-) - -diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h -index ae31a8a631fc..a86f74b59360 100644 ---- a/security/apparmor/include/match.h -+++ b/security/apparmor/include/match.h -@@ -181,6 +181,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa) - #define MATCH_FLAG_DIFF_ENCODE 0x80000000 - #define MARK_DIFF_ENCODE 0x40000000 - #define MATCH_FLAG_OOB_TRANSITION 0x20000000 -+#define MARK_DIFF_ENCODE_VERIFIED 0x10000000 - #define MATCH_FLAGS_MASK 0xff000000 - #define MATCH_FLAGS_VALID (MATCH_FLAG_DIFF_ENCODE | MATCH_FLAG_OOB_TRANSITION) - #define MATCH_FLAGS_INVALID (MATCH_FLAGS_MASK & ~MATCH_FLAGS_VALID) -diff --git a/security/apparmor/match.c b/security/apparmor/match.c -index 98cf3b1f1649..a37a5649802b 100644 ---- a/security/apparmor/match.c -+++ b/security/apparmor/match.c -@@ -202,16 +202,31 @@ static int verify_dfa(struct aa_dfa *dfa) - size_t j, k; - - for (j = i; -- (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && -- !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); -+ ((BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && -+ !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE_VERIFIED)); - j = k) { -+ if (BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE) -+ /* loop in current chain */ -+ goto out; - k = DEFAULT_TABLE(dfa)[j]; - if (j == k) -+ /* self loop */ - goto out; -- if (k < j) -- break; /* already verified */ - BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; - } -+ /* move mark to verified */ -+ for (j = i; -+ (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE); -+ j = k) { -+ k = DEFAULT_TABLE(dfa)[j]; -+ if (j < i) -+ /* jumps to state/chain that has been -+ * verified -+ */ -+ break; -+ BASE_TABLE(dfa)[j] &= ~MARK_DIFF_ENCODE; -+ BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE_VERIFIED; -+ } - } - error = 0; - --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0010-apparmor-fix-race-on-rawdata-dereference.patch b/patches-sonic/qsa-2026-apparmor/0010-apparmor-fix-race-on-rawdata-dereference.patch deleted file mode 100644 index 00a52913a..000000000 --- a/patches-sonic/qsa-2026-apparmor/0010-apparmor-fix-race-on-rawdata-dereference.patch +++ /dev/null @@ -1,446 +0,0 @@ -From c88a5ec7c46387ceab1f9d550c035a76faf0f3d1 Mon Sep 17 00:00:00 2001 -From: John Johansen -Date: Tue, 24 Feb 2026 10:20:02 -0800 -Subject: [PATCH 10/11] apparmor: fix race on rawdata dereference -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There is a race condition that leads to a use-after-free situation: -because the rawdata inodes are not refcounted, an attacker can start -open()ing one of the rawdata files, and at the same time remove the -last reference to this rawdata (by removing the corresponding profile, -for example), which frees its struct aa_loaddata; as a result, when -seq_rawdata_open() is reached, i_private is a dangling pointer and -freed memory is accessed. - -The rawdata inodes weren't refcounted to avoid a circular refcount and -were supposed to be held by the profile rawdata reference. However -during profile removal there is a window where the vfs and profile -destruction race, resulting in the use after free. - -Fix this by moving to a double refcount scheme. Where the profile -refcount on rawdata is used to break the circular dependency. Allowing -for freeing of the rawdata once all inode references to the rawdata -are put. - -Fixes: 5d5182cae401 ("apparmor: move to per loaddata files, instead of replicating in profiles") -Reported-by: Qualys Security Advisory -Reviewed-by: Georgia Garcia -Reviewed-by: Maxime Bélair -Reviewed-by: Cengiz Can -Tested-by: Salvatore Bonaccorso -Signed-off-by: John Johansen ---- - security/apparmor/apparmorfs.c | 35 ++++++----- - security/apparmor/include/policy_unpack.h | 71 ++++++++++++++--------- - security/apparmor/policy.c | 12 ++-- - security/apparmor/policy_unpack.c | 32 +++++++--- - 4 files changed, 93 insertions(+), 57 deletions(-) - -diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c -index c708f0bfe594..45f44978537e 100644 ---- a/security/apparmor/apparmorfs.c -+++ b/security/apparmor/apparmorfs.c -@@ -79,7 +79,7 @@ static void rawdata_f_data_free(struct rawdata_f_data *private) - if (!private) - return; - -- aa_put_loaddata(private->loaddata); -+ aa_put_i_loaddata(private->loaddata); - kvfree(private); - } - -@@ -404,7 +404,8 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, - - data->size = copy_size; - if (copy_from_user(data->data, userbuf, copy_size)) { -- aa_put_loaddata(data); -+ /* trigger free - don't need to put pcount */ -+ aa_put_i_loaddata(data); - return ERR_PTR(-EFAULT); - } - -@@ -432,7 +433,10 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, - error = PTR_ERR(data); - if (!IS_ERR(data)) { - error = aa_replace_profiles(ns, label, mask, data); -- aa_put_loaddata(data); -+ /* put pcount, which will put count and free if no -+ * profiles referencing it. -+ */ -+ aa_put_profile_loaddata(data); - } - end_section: - end_current_label_crit_section(label); -@@ -503,7 +507,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, - if (!IS_ERR(data)) { - data->data[size] = 0; - error = aa_remove_profiles(ns, label, data->data, size); -- aa_put_loaddata(data); -+ aa_put_profile_loaddata(data); - } - out: - end_current_label_crit_section(label); -@@ -1242,18 +1246,17 @@ static const struct file_operations seq_rawdata_ ##NAME ##_fops = { \ - static int seq_rawdata_open(struct inode *inode, struct file *file, - int (*show)(struct seq_file *, void *)) - { -- struct aa_loaddata *data = __aa_get_loaddata(inode->i_private); -+ struct aa_loaddata *data = aa_get_i_loaddata(inode->i_private); - int error; - - if (!data) -- /* lost race this ent is being reaped */ - return -ENOENT; - - error = single_open(file, show, data); - if (error) { - AA_BUG(file->private_data && - ((struct seq_file *)file->private_data)->private); -- aa_put_loaddata(data); -+ aa_put_i_loaddata(data); - } - - return error; -@@ -1264,7 +1267,7 @@ static int seq_rawdata_release(struct inode *inode, struct file *file) - struct seq_file *seq = (struct seq_file *) file->private_data; - - if (seq) -- aa_put_loaddata(seq->private); -+ aa_put_i_loaddata(seq->private); - - return single_release(inode, file); - } -@@ -1376,9 +1379,8 @@ static int rawdata_open(struct inode *inode, struct file *file) - if (!aa_current_policy_view_capable(NULL)) - return -EACCES; - -- loaddata = __aa_get_loaddata(inode->i_private); -+ loaddata = aa_get_i_loaddata(inode->i_private); - if (!loaddata) -- /* lost race: this entry is being reaped */ - return -ENOENT; - - private = rawdata_f_data_alloc(loaddata->size); -@@ -1403,7 +1405,7 @@ static int rawdata_open(struct inode *inode, struct file *file) - return error; - - fail_private_alloc: -- aa_put_loaddata(loaddata); -+ aa_put_i_loaddata(loaddata); - return error; - } - -@@ -1420,9 +1422,9 @@ static void remove_rawdata_dents(struct aa_loaddata *rawdata) - - for (i = 0; i < AAFS_LOADDATA_NDENTS; i++) { - if (!IS_ERR_OR_NULL(rawdata->dents[i])) { -- /* no refcounts on i_private */ - aafs_remove(rawdata->dents[i]); - rawdata->dents[i] = NULL; -+ aa_put_i_loaddata(rawdata); - } - } - } -@@ -1461,18 +1463,21 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) - if (IS_ERR(dir)) - /* ->name freed when rawdata freed */ - return PTR_ERR(dir); -+ aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_DIR] = dir; - - dent = aafs_create_file("abi", S_IFREG | 0444, dir, rawdata, - &seq_rawdata_abi_fops); - if (IS_ERR(dent)) - goto fail; -+ aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_ABI] = dent; - - dent = aafs_create_file("revision", S_IFREG | 0444, dir, rawdata, - &seq_rawdata_revision_fops); - if (IS_ERR(dent)) - goto fail; -+ aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_REVISION] = dent; - - if (aa_g_hash_policy) { -@@ -1480,6 +1485,7 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) - rawdata, &seq_rawdata_hash_fops); - if (IS_ERR(dent)) - goto fail; -+ aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_HASH] = dent; - } - -@@ -1488,24 +1494,25 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) - &seq_rawdata_compressed_size_fops); - if (IS_ERR(dent)) - goto fail; -+ aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_COMPRESSED_SIZE] = dent; - - dent = aafs_create_file("raw_data", S_IFREG | 0444, - dir, rawdata, &rawdata_fops); - if (IS_ERR(dent)) - goto fail; -+ aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_DATA] = dent; - d_inode(dent)->i_size = rawdata->size; - - rawdata->ns = aa_get_ns(ns); - list_add(&rawdata->list, &ns->rawdata_list); -- /* no refcount on inode rawdata */ - - return 0; - - fail: - remove_rawdata_dents(rawdata); -- -+ aa_put_i_loaddata(rawdata); - return PTR_ERR(dent); - } - #endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ -diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h -index a6f4611ee50c..4f800fbb805a 100644 ---- a/security/apparmor/include/policy_unpack.h -+++ b/security/apparmor/include/policy_unpack.h -@@ -87,17 +87,29 @@ struct aa_ext { - u32 version; - }; - --/* -- * struct aa_loaddata - buffer of policy raw_data set -+/* struct aa_loaddata - buffer of policy raw_data set -+ * @count: inode/filesystem refcount - use aa_get_i_loaddata() -+ * @pcount: profile refcount - use aa_get_profile_loaddata() -+ * @list: list the loaddata is on -+ * @work: used to do a delayed cleanup -+ * @dents: refs to dents created in aafs -+ * @ns: the namespace this loaddata was loaded into -+ * @name: -+ * @size: the size of the data that was loaded -+ * @compressed_size: the size of the data when it is compressed -+ * @revision: unique revision count that this data was loaded as -+ * @abi: the abi number the loaddata uses -+ * @hash: a hash of the loaddata, used to help dedup data - * -- * there is no loaddata ref for being on ns list, nor a ref from -- * d_inode(@dentry) when grab a ref from these, @ns->lock must be held -- * && __aa_get_loaddata() needs to be used, and the return value -- * checked, if NULL the loaddata is already being reaped and should be -- * considered dead. -+ * There is no loaddata ref for being on ns->rawdata_list, so -+ * @ns->lock must be held when walking the list. Dentries and -+ * inode opens hold refs on @count; profiles hold refs on @pcount. -+ * When the last @pcount drops, do_ploaddata_rmfs() removes the -+ * fs entries and drops the associated @count ref. - */ - struct aa_loaddata { - struct kref count; -+ struct kref pcount; - struct list_head list; - struct work_struct work; - struct dentry *dents[AAFS_LOADDATA_NDENTS]; -@@ -119,52 +131,55 @@ struct aa_loaddata { - int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns); - - /** -- * __aa_get_loaddata - get a reference count to uncounted data reference -+ * aa_get_loaddata - get a reference count from a counted data reference - * @data: reference to get a count on - * -- * Returns: pointer to reference OR NULL if race is lost and reference is -- * being repeated. -- * Requires: @data->ns->lock held, and the return code MUST be checked -- * -- * Use only from inode->i_private and @data->list found references -+ * Returns: pointer to reference -+ * Requires: @data to have a valid reference count on it. It is a bug -+ * if the race to reap can be encountered when it is used. - */ - static inline struct aa_loaddata * --__aa_get_loaddata(struct aa_loaddata *data) -+aa_get_i_loaddata(struct aa_loaddata *data) - { -- if (data && kref_get_unless_zero(&(data->count))) -- return data; - -- return NULL; -+ if (data) -+ kref_get(&(data->count)); -+ return data; - } - -+ - /** -- * aa_get_loaddata - get a reference count from a counted data reference -+ * aa_get_profile_loaddata - get a profile reference count on loaddata - * @data: reference to get a count on - * -- * Returns: point to reference -- * Requires: @data to have a valid reference count on it. It is a bug -- * if the race to reap can be encountered when it is used. -+ * Returns: pointer to reference -+ * Requires: @data to have a valid reference count on it. - */ - static inline struct aa_loaddata * --aa_get_loaddata(struct aa_loaddata *data) -+aa_get_profile_loaddata(struct aa_loaddata *data) - { -- struct aa_loaddata *tmp = __aa_get_loaddata(data); -- -- AA_BUG(data && !tmp); -- -- return tmp; -+ if (data) -+ kref_get(&(data->pcount)); -+ return data; - } - - void __aa_loaddata_update(struct aa_loaddata *data, long revision); - bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r); - void aa_loaddata_kref(struct kref *kref); -+void aa_ploaddata_kref(struct kref *kref); - struct aa_loaddata *aa_loaddata_alloc(size_t size); --static inline void aa_put_loaddata(struct aa_loaddata *data) -+static inline void aa_put_i_loaddata(struct aa_loaddata *data) - { - if (data) - kref_put(&data->count, aa_loaddata_kref); - } - -+static inline void aa_put_profile_loaddata(struct aa_loaddata *data) -+{ -+ if (data) -+ kref_put(&data->pcount, aa_ploaddata_kref); -+} -+ - #if IS_ENABLED(CONFIG_KUNIT) - bool aa_inbounds(struct aa_ext *e, size_t size); - size_t aa_unpack_u16_chunk(struct aa_ext *e, char **chunk); -diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c -index 29f1cfd75090..b5ae0314b384 100644 ---- a/security/apparmor/policy.c -+++ b/security/apparmor/policy.c -@@ -338,7 +338,7 @@ void aa_free_profile(struct aa_profile *profile) - } - - kfree_sensitive(profile->hash); -- aa_put_loaddata(profile->rawdata); -+ aa_put_profile_loaddata(profile->rawdata); - aa_label_destroy(&profile->label); - - kfree_sensitive(profile); -@@ -1123,7 +1123,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, - LIST_HEAD(lh); - - op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD; -- aa_get_loaddata(udata); -+ aa_get_profile_loaddata(udata); - /* released below */ - error = aa_unpack(udata, &lh, &ns_name); - if (error) -@@ -1175,10 +1175,10 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, - if (aa_rawdata_eq(rawdata_ent, udata)) { - struct aa_loaddata *tmp; - -- tmp = __aa_get_loaddata(rawdata_ent); -+ tmp = aa_get_profile_loaddata(rawdata_ent); - /* check we didn't fail the race */ - if (tmp) { -- aa_put_loaddata(udata); -+ aa_put_profile_loaddata(udata); - udata = tmp; - break; - } -@@ -1191,7 +1191,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, - struct aa_profile *p; - - if (aa_g_export_binary) -- ent->new->rawdata = aa_get_loaddata(udata); -+ ent->new->rawdata = aa_get_profile_loaddata(udata); - error = __lookup_replace(ns, ent->new->base.hname, - !(mask & AA_MAY_REPLACE_POLICY), - &ent->old, &info); -@@ -1324,7 +1324,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, - - out: - aa_put_ns(ns); -- aa_put_loaddata(udata); -+ aa_put_profile_loaddata(udata); - kfree(ns_name); - - if (error) -diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c -index 0232fc29a234..36175b99914b 100644 ---- a/security/apparmor/policy_unpack.c -+++ b/security/apparmor/policy_unpack.c -@@ -108,34 +108,47 @@ bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r) - return memcmp(l->data, r->data, r->compressed_size ?: r->size) == 0; - } - -+static void do_loaddata_free(struct aa_loaddata *d) -+{ -+ kfree_sensitive(d->hash); -+ kfree_sensitive(d->name); -+ kvfree(d->data); -+ kfree_sensitive(d); -+} -+ -+void aa_loaddata_kref(struct kref *kref) -+{ -+ struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count); -+ -+ do_loaddata_free(d); -+} -+ - /* - * need to take the ns mutex lock which is NOT safe most places that - * put_loaddata is called, so we have to delay freeing it - */ --static void do_loaddata_free(struct work_struct *work) -+static void do_ploaddata_rmfs(struct work_struct *work) - { - struct aa_loaddata *d = container_of(work, struct aa_loaddata, work); - struct aa_ns *ns = aa_get_ns(d->ns); - - if (ns) { - mutex_lock_nested(&ns->lock, ns->level); -+ /* remove fs ref to loaddata */ - __aa_fs_remove_rawdata(d); - mutex_unlock(&ns->lock); - aa_put_ns(ns); - } -- -- kfree_sensitive(d->hash); -- kfree_sensitive(d->name); -- kvfree(d->data); -- kfree_sensitive(d); -+ /* called by dropping last pcount, so drop its associated icount */ -+ aa_put_i_loaddata(d); - } - --void aa_loaddata_kref(struct kref *kref) -+void aa_ploaddata_kref(struct kref *kref) - { -- struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count); -+ struct aa_loaddata *d = container_of(kref, struct aa_loaddata, pcount); - - if (d) { -- INIT_WORK(&d->work, do_loaddata_free); -+ INIT_WORK(&d->work, do_ploaddata_rmfs); - schedule_work(&d->work); - } - } -@@ -153,6 +166,7 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size) - return ERR_PTR(-ENOMEM); - } - kref_init(&d->count); -+ kref_init(&d->pcount); - INIT_LIST_HEAD(&d->list); - - return d; --- -2.53.0 - diff --git a/patches-sonic/qsa-2026-apparmor/0011-apparmor-fix-race-between-freeing-data-and-fs-access.patch b/patches-sonic/qsa-2026-apparmor/0011-apparmor-fix-race-between-freeing-data-and-fs-access.patch deleted file mode 100644 index d82fa012e..000000000 --- a/patches-sonic/qsa-2026-apparmor/0011-apparmor-fix-race-between-freeing-data-and-fs-access.patch +++ /dev/null @@ -1,717 +0,0 @@ -From 070021c421ed59f4886aad6a3e80f636227d62e5 Mon Sep 17 00:00:00 2001 -From: John Johansen -Date: Sun, 1 Mar 2026 16:10:51 -0800 -Subject: [PATCH 11/11] apparmor: fix race between freeing data and fs - accessing it -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -AppArmor was putting the reference to i_private data on its end after -removing the original entry from the file system. However the inode -can and does live beyond that point and it is possible that some of -the fs call back functions will be invoked after the reference has -been put, which results in a race between freeing the data and -accessing it through the fs. - -While the rawdata/loaddata is the most likely candidate to fail the -race, as it has the fewest references. If properly crafted it might be -possible to trigger a race for the other types stored in i_private. - -Fix this by moving the put of i_private referenced data to the correct -place which is during inode eviction. - -Fixes: c961ee5f21b20 ("apparmor: convert from securityfs to apparmorfs for policy ns files") -Reported-by: Qualys Security Advisory -Reviewed-by: Georgia Garcia -Reviewed-by: Maxime Bélair -Reviewed-by: Cengiz Can -Signed-off-by: John Johansen ---- - security/apparmor/apparmorfs.c | 194 +++++++++++++--------- - security/apparmor/include/label.h | 16 +- - security/apparmor/include/lib.h | 12 ++ - security/apparmor/include/policy.h | 8 +- - security/apparmor/include/policy_unpack.h | 6 +- - security/apparmor/label.c | 12 +- - security/apparmor/policy_unpack.c | 6 +- - 7 files changed, 153 insertions(+), 101 deletions(-) - -diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c -index 45f44978537e..c70e1daad21a 100644 ---- a/security/apparmor/apparmorfs.c -+++ b/security/apparmor/apparmorfs.c -@@ -32,6 +32,7 @@ - #include "include/crypto.h" - #include "include/ipc.h" - #include "include/label.h" -+#include "include/lib.h" - #include "include/policy.h" - #include "include/policy_ns.h" - #include "include/resource.h" -@@ -62,6 +63,7 @@ - * securityfs and apparmorfs filesystems. - */ - -+#define IREF_POISON 101 - - /* - * support fns -@@ -153,6 +155,71 @@ static int aafs_show_path(struct seq_file *seq, struct dentry *dentry) - return 0; - } - -+static struct aa_ns *get_ns_common_ref(struct aa_common_ref *ref) -+{ -+ if (ref) { -+ struct aa_label *reflabel = container_of(ref, struct aa_label, -+ count); -+ return aa_get_ns(labels_ns(reflabel)); -+ } -+ -+ return NULL; -+} -+ -+static struct aa_proxy *get_proxy_common_ref(struct aa_common_ref *ref) -+{ -+ if (ref) -+ return aa_get_proxy(container_of(ref, struct aa_proxy, count)); -+ -+ return NULL; -+} -+ -+static struct aa_loaddata *get_loaddata_common_ref(struct aa_common_ref *ref) -+{ -+ if (ref) -+ return aa_get_i_loaddata(container_of(ref, struct aa_loaddata, -+ count)); -+ return NULL; -+} -+ -+static void aa_put_common_ref(struct aa_common_ref *ref) -+{ -+ if (!ref) -+ return; -+ -+ switch (ref->reftype) { -+ case REF_RAWDATA: -+ aa_put_i_loaddata(container_of(ref, struct aa_loaddata, -+ count)); -+ break; -+ case REF_PROXY: -+ aa_put_proxy(container_of(ref, struct aa_proxy, -+ count)); -+ break; -+ case REF_NS: -+ /* ns count is held on its unconfined label */ -+ aa_put_ns(labels_ns(container_of(ref, struct aa_label, count))); -+ break; -+ default: -+ AA_BUG(true, "unknown refcount type"); -+ break; -+ } -+} -+ -+static void aa_get_common_ref(struct aa_common_ref *ref) -+{ -+ kref_get(&ref->count); -+} -+ -+static void aafs_evict(struct inode *inode) -+{ -+ struct aa_common_ref *ref = inode->i_private; -+ -+ clear_inode(inode); -+ aa_put_common_ref(ref); -+ inode->i_private = (void *) IREF_POISON; -+} -+ - static void aafs_free_inode(struct inode *inode) - { - if (S_ISLNK(inode->i_mode)) -@@ -162,6 +229,7 @@ static void aafs_free_inode(struct inode *inode) - - static const struct super_operations aafs_super_ops = { - .statfs = simple_statfs, -+ .evict_inode = aafs_evict, - .free_inode = aafs_free_inode, - .show_path = aafs_show_path, - }; -@@ -262,7 +330,8 @@ static int __aafs_setup_d_inode(struct inode *dir, struct dentry *dentry, - * aafs_remove(). Will return ERR_PTR on failure. - */ - static struct dentry *aafs_create(const char *name, umode_t mode, -- struct dentry *parent, void *data, void *link, -+ struct dentry *parent, -+ struct aa_common_ref *data, void *link, - const struct file_operations *fops, - const struct inode_operations *iops) - { -@@ -299,6 +368,9 @@ static struct dentry *aafs_create(const char *name, umode_t mode, - goto fail_dentry; - inode_unlock(dir); - -+ if (data) -+ aa_get_common_ref(data); -+ - return dentry; - - fail_dentry: -@@ -323,7 +395,8 @@ static struct dentry *aafs_create(const char *name, umode_t mode, - * see aafs_create - */ - static struct dentry *aafs_create_file(const char *name, umode_t mode, -- struct dentry *parent, void *data, -+ struct dentry *parent, -+ struct aa_common_ref *data, - const struct file_operations *fops) - { - return aafs_create(name, mode, parent, data, NULL, fops, NULL); -@@ -448,7 +521,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, - static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, - loff_t *pos) - { -- struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); -+ struct aa_ns *ns = get_ns_common_ref(f->f_inode->i_private); - int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns, - f->f_cred); - -@@ -466,7 +539,7 @@ static const struct file_operations aa_fs_profile_load = { - static ssize_t profile_replace(struct file *f, const char __user *buf, - size_t size, loff_t *pos) - { -- struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); -+ struct aa_ns *ns = get_ns_common_ref(f->f_inode->i_private); - int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY, - buf, size, pos, ns, f->f_cred); - aa_put_ns(ns); -@@ -486,7 +559,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, - struct aa_loaddata *data; - struct aa_label *label; - ssize_t error; -- struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); -+ struct aa_ns *ns = get_ns_common_ref(f->f_inode->i_private); - - label = begin_current_label_crit_section(); - /* high level check about policy management - fine grained in -@@ -576,7 +649,7 @@ static int ns_revision_open(struct inode *inode, struct file *file) - if (!rev) - return -ENOMEM; - -- rev->ns = aa_get_ns(inode->i_private); -+ rev->ns = get_ns_common_ref(inode->i_private); - if (!rev->ns) - rev->ns = aa_get_current_ns(); - file->private_data = rev; -@@ -1054,7 +1127,7 @@ static const struct file_operations seq_profile_ ##NAME ##_fops = { \ - static int seq_profile_open(struct inode *inode, struct file *file, - int (*show)(struct seq_file *, void *)) - { -- struct aa_proxy *proxy = aa_get_proxy(inode->i_private); -+ struct aa_proxy *proxy = get_proxy_common_ref(inode->i_private); - int error = single_open(file, show, proxy); - - if (error) { -@@ -1246,7 +1319,7 @@ static const struct file_operations seq_rawdata_ ##NAME ##_fops = { \ - static int seq_rawdata_open(struct inode *inode, struct file *file, - int (*show)(struct seq_file *, void *)) - { -- struct aa_loaddata *data = aa_get_i_loaddata(inode->i_private); -+ struct aa_loaddata *data = get_loaddata_common_ref(inode->i_private); - int error; - - if (!data) -@@ -1379,7 +1452,7 @@ static int rawdata_open(struct inode *inode, struct file *file) - if (!aa_current_policy_view_capable(NULL)) - return -EACCES; - -- loaddata = aa_get_i_loaddata(inode->i_private); -+ loaddata = get_loaddata_common_ref(inode->i_private); - if (!loaddata) - return -ENOENT; - -@@ -1424,7 +1497,6 @@ static void remove_rawdata_dents(struct aa_loaddata *rawdata) - if (!IS_ERR_OR_NULL(rawdata->dents[i])) { - aafs_remove(rawdata->dents[i]); - rawdata->dents[i] = NULL; -- aa_put_i_loaddata(rawdata); - } - } - } -@@ -1463,45 +1535,41 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) - if (IS_ERR(dir)) - /* ->name freed when rawdata freed */ - return PTR_ERR(dir); -- aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_DIR] = dir; - -- dent = aafs_create_file("abi", S_IFREG | 0444, dir, rawdata, -+ dent = aafs_create_file("abi", S_IFREG | 0444, dir, &rawdata->count, - &seq_rawdata_abi_fops); - if (IS_ERR(dent)) - goto fail; -- aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_ABI] = dent; - -- dent = aafs_create_file("revision", S_IFREG | 0444, dir, rawdata, -- &seq_rawdata_revision_fops); -+ dent = aafs_create_file("revision", S_IFREG | 0444, dir, -+ &rawdata->count, -+ &seq_rawdata_revision_fops); - if (IS_ERR(dent)) - goto fail; -- aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_REVISION] = dent; - - if (aa_g_hash_policy) { - dent = aafs_create_file("sha256", S_IFREG | 0444, dir, -- rawdata, &seq_rawdata_hash_fops); -+ &rawdata->count, -+ &seq_rawdata_hash_fops); - if (IS_ERR(dent)) - goto fail; -- aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_HASH] = dent; - } - - dent = aafs_create_file("compressed_size", S_IFREG | 0444, dir, -- rawdata, -+ &rawdata->count, - &seq_rawdata_compressed_size_fops); - if (IS_ERR(dent)) - goto fail; -- aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_COMPRESSED_SIZE] = dent; - -- dent = aafs_create_file("raw_data", S_IFREG | 0444, -- dir, rawdata, &rawdata_fops); -+ dent = aafs_create_file("raw_data", S_IFREG | 0444, dir, -+ &rawdata->count, &rawdata_fops); - if (IS_ERR(dent)) - goto fail; -- aa_get_i_loaddata(rawdata); - rawdata->dents[AAFS_LOADDATA_DATA] = dent; - d_inode(dent)->i_size = rawdata->size; - -@@ -1512,7 +1580,6 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) - - fail: - remove_rawdata_dents(rawdata); -- aa_put_i_loaddata(rawdata); - return PTR_ERR(dent); - } - #endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ -@@ -1536,13 +1603,10 @@ void __aafs_profile_rmdir(struct aa_profile *profile) - __aafs_profile_rmdir(child); - - for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) { -- struct aa_proxy *proxy; - if (!profile->dents[i]) - continue; - -- proxy = d_inode(profile->dents[i])->i_private; - aafs_remove(profile->dents[i]); -- aa_put_proxy(proxy); - profile->dents[i] = NULL; - } - } -@@ -1576,14 +1640,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, - struct aa_profile *profile, - const struct file_operations *fops) - { -- struct aa_proxy *proxy = aa_get_proxy(profile->label.proxy); -- struct dentry *dent; -- -- dent = aafs_create_file(name, S_IFREG | 0444, dir, proxy, fops); -- if (IS_ERR(dent)) -- aa_put_proxy(proxy); -- -- return dent; -+ return aafs_create_file(name, S_IFREG | 0444, dir, &profile->label.proxy->count, fops); - } - - #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY -@@ -1629,7 +1686,8 @@ static const char *rawdata_get_link_base(struct dentry *dentry, - struct delayed_call *done, - const char *name) - { -- struct aa_proxy *proxy = inode->i_private; -+ struct aa_common_ref *ref = inode->i_private; -+ struct aa_proxy *proxy = container_of(ref, struct aa_proxy, count); - struct aa_label *label; - struct aa_profile *profile; - char *target; -@@ -1762,27 +1820,24 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) - if (profile->rawdata) { - if (aa_g_hash_policy) { - dent = aafs_create("raw_sha256", S_IFLNK | 0444, dir, -- profile->label.proxy, NULL, NULL, -- &rawdata_link_sha256_iops); -+ &profile->label.proxy->count, NULL, -+ NULL, &rawdata_link_sha256_iops); - if (IS_ERR(dent)) - goto fail; -- aa_get_proxy(profile->label.proxy); - profile->dents[AAFS_PROF_RAW_HASH] = dent; - } - dent = aafs_create("raw_abi", S_IFLNK | 0444, dir, -- profile->label.proxy, NULL, NULL, -+ &profile->label.proxy->count, NULL, NULL, - &rawdata_link_abi_iops); - if (IS_ERR(dent)) - goto fail; -- aa_get_proxy(profile->label.proxy); - profile->dents[AAFS_PROF_RAW_ABI] = dent; - - dent = aafs_create("raw_data", S_IFLNK | 0444, dir, -- profile->label.proxy, NULL, NULL, -+ &profile->label.proxy->count, NULL, NULL, - &rawdata_link_data_iops); - if (IS_ERR(dent)) - goto fail; -- aa_get_proxy(profile->label.proxy); - profile->dents[AAFS_PROF_RAW_DATA] = dent; - } - #endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ -@@ -1819,7 +1874,7 @@ static int ns_mkdir_op(struct mnt_idmap *idmap, struct inode *dir, - if (error) - return error; - -- parent = aa_get_ns(dir->i_private); -+ parent = get_ns_common_ref(dir->i_private); - AA_BUG(d_inode(ns_subns_dir(parent)) != dir); - - /* we have to unlock and then relock to get locking order right -@@ -1869,7 +1924,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) - if (error) - return error; - -- parent = aa_get_ns(dir->i_private); -+ parent = get_ns_common_ref(dir->i_private); - /* rmdir calls the generic securityfs functions to remove files - * from the apparmor dir. It is up to the apparmor ns locking - * to avoid races. -@@ -1939,27 +1994,6 @@ void __aafs_ns_rmdir(struct aa_ns *ns) - - __aa_fs_list_remove_rawdata(ns); - -- if (ns_subns_dir(ns)) { -- sub = d_inode(ns_subns_dir(ns))->i_private; -- aa_put_ns(sub); -- } -- if (ns_subload(ns)) { -- sub = d_inode(ns_subload(ns))->i_private; -- aa_put_ns(sub); -- } -- if (ns_subreplace(ns)) { -- sub = d_inode(ns_subreplace(ns))->i_private; -- aa_put_ns(sub); -- } -- if (ns_subremove(ns)) { -- sub = d_inode(ns_subremove(ns))->i_private; -- aa_put_ns(sub); -- } -- if (ns_subrevision(ns)) { -- sub = d_inode(ns_subrevision(ns))->i_private; -- aa_put_ns(sub); -- } -- - for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) { - aafs_remove(ns->dents[i]); - ns->dents[i] = NULL; -@@ -1984,40 +2018,40 @@ static int __aafs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir) - return PTR_ERR(dent); - ns_subdata_dir(ns) = dent; - -- dent = aafs_create_file("revision", 0444, dir, ns, -+ dent = aafs_create_file("revision", 0444, dir, -+ &ns->unconfined->label.count, - &aa_fs_ns_revision_fops); - if (IS_ERR(dent)) - return PTR_ERR(dent); -- aa_get_ns(ns); - ns_subrevision(ns) = dent; - -- dent = aafs_create_file(".load", 0640, dir, ns, -- &aa_fs_profile_load); -+ dent = aafs_create_file(".load", 0640, dir, -+ &ns->unconfined->label.count, -+ &aa_fs_profile_load); - if (IS_ERR(dent)) - return PTR_ERR(dent); -- aa_get_ns(ns); - ns_subload(ns) = dent; - -- dent = aafs_create_file(".replace", 0640, dir, ns, -- &aa_fs_profile_replace); -+ dent = aafs_create_file(".replace", 0640, dir, -+ &ns->unconfined->label.count, -+ &aa_fs_profile_replace); - if (IS_ERR(dent)) - return PTR_ERR(dent); -- aa_get_ns(ns); - ns_subreplace(ns) = dent; - -- dent = aafs_create_file(".remove", 0640, dir, ns, -- &aa_fs_profile_remove); -+ dent = aafs_create_file(".remove", 0640, dir, -+ &ns->unconfined->label.count, -+ &aa_fs_profile_remove); - if (IS_ERR(dent)) - return PTR_ERR(dent); -- aa_get_ns(ns); - ns_subremove(ns) = dent; - - /* use create_dentry so we can supply private data */ -- dent = aafs_create("namespaces", S_IFDIR | 0755, dir, ns, NULL, NULL, -- &ns_dir_inode_operations); -+ dent = aafs_create("namespaces", S_IFDIR | 0755, dir, -+ &ns->unconfined->label.count, -+ NULL, NULL, &ns_dir_inode_operations); - if (IS_ERR(dent)) - return PTR_ERR(dent); -- aa_get_ns(ns); - ns_subns_dir(ns) = dent; - - return 0; -diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h -index 2a72e6b17d68..5aca0f612f8f 100644 ---- a/security/apparmor/include/label.h -+++ b/security/apparmor/include/label.h -@@ -101,7 +101,7 @@ enum label_flags { - - struct aa_label; - struct aa_proxy { -- struct kref count; -+ struct aa_common_ref count; - struct aa_label __rcu *label; - }; - -@@ -121,7 +121,7 @@ struct label_it { - * @ent: set of profiles for label, actual size determined by @size - */ - struct aa_label { -- struct kref count; -+ struct aa_common_ref count; - struct rb_node node; - struct rcu_head rcu; - struct aa_proxy *proxy; -@@ -373,7 +373,7 @@ int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules, - */ - static inline struct aa_label *__aa_get_label(struct aa_label *l) - { -- if (l && kref_get_unless_zero(&l->count)) -+ if (l && kref_get_unless_zero(&l->count.count)) - return l; - - return NULL; -@@ -382,7 +382,7 @@ static inline struct aa_label *__aa_get_label(struct aa_label *l) - static inline struct aa_label *aa_get_label(struct aa_label *l) - { - if (l) -- kref_get(&(l->count)); -+ kref_get(&(l->count.count)); - - return l; - } -@@ -402,7 +402,7 @@ static inline struct aa_label *aa_get_label_rcu(struct aa_label __rcu **l) - rcu_read_lock(); - do { - c = rcu_dereference(*l); -- } while (c && !kref_get_unless_zero(&c->count)); -+ } while (c && !kref_get_unless_zero(&c->count.count)); - rcu_read_unlock(); - - return c; -@@ -442,7 +442,7 @@ static inline struct aa_label *aa_get_newest_label(struct aa_label *l) - static inline void aa_put_label(struct aa_label *l) - { - if (l) -- kref_put(&l->count, aa_label_kref); -+ kref_put(&l->count.count, aa_label_kref); - } - - -@@ -452,7 +452,7 @@ void aa_proxy_kref(struct kref *kref); - static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *proxy) - { - if (proxy) -- kref_get(&(proxy->count)); -+ kref_get(&(proxy->count.count)); - - return proxy; - } -@@ -460,7 +460,7 @@ static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *proxy) - static inline void aa_put_proxy(struct aa_proxy *proxy) - { - if (proxy) -- kref_put(&proxy->count, aa_proxy_kref); -+ kref_put(&proxy->count.count, aa_proxy_kref); - } - - void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new); -diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h -index 1ec00113a056..e76470c8b84c 100644 ---- a/security/apparmor/include/lib.h -+++ b/security/apparmor/include/lib.h -@@ -71,6 +71,18 @@ void aa_info_message(const char *str); - /* Security blob offsets */ - extern struct lsm_blob_sizes apparmor_blob_sizes; - -+enum reftype { -+ REF_NS, -+ REF_PROXY, -+ REF_RAWDATA, -+}; -+ -+/* common reference count used by data the shows up in aafs */ -+struct aa_common_ref { -+ struct kref count; -+ enum reftype reftype; -+}; -+ - /** - * aa_strneq - compare null terminated @str to a non null terminated substring - * @str: a null terminated string -diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h -index b8c35972883c..dbd6af6034f1 100644 ---- a/security/apparmor/include/policy.h -+++ b/security/apparmor/include/policy.h -@@ -329,7 +329,7 @@ static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head, - static inline struct aa_profile *aa_get_profile(struct aa_profile *p) - { - if (p) -- kref_get(&(p->label.count)); -+ kref_get(&(p->label.count.count)); - - return p; - } -@@ -343,7 +343,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p) - */ - static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p) - { -- if (p && kref_get_unless_zero(&p->label.count)) -+ if (p && kref_get_unless_zero(&p->label.count.count)) - return p; - - return NULL; -@@ -363,7 +363,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p) - rcu_read_lock(); - do { - c = rcu_dereference(*p); -- } while (c && !kref_get_unless_zero(&c->label.count)); -+ } while (c && !kref_get_unless_zero(&c->label.count.count)); - rcu_read_unlock(); - - return c; -@@ -376,7 +376,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p) - static inline void aa_put_profile(struct aa_profile *p) - { - if (p) -- kref_put(&p->label.count, aa_label_kref); -+ kref_put(&p->label.count.count, aa_label_kref); - } - - static inline int AUDIT_MODE(struct aa_profile *profile) -diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h -index 4f800fbb805a..e5a95dc4da1f 100644 ---- a/security/apparmor/include/policy_unpack.h -+++ b/security/apparmor/include/policy_unpack.h -@@ -108,7 +108,7 @@ struct aa_ext { - * fs entries and drops the associated @count ref. - */ - struct aa_loaddata { -- struct kref count; -+ struct aa_common_ref count; - struct kref pcount; - struct list_head list; - struct work_struct work; -@@ -143,7 +143,7 @@ aa_get_i_loaddata(struct aa_loaddata *data) - { - - if (data) -- kref_get(&(data->count)); -+ kref_get(&(data->count.count)); - return data; - } - -@@ -171,7 +171,7 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size); - static inline void aa_put_i_loaddata(struct aa_loaddata *data) - { - if (data) -- kref_put(&data->count, aa_loaddata_kref); -+ kref_put(&data->count.count, aa_loaddata_kref); - } - - static inline void aa_put_profile_loaddata(struct aa_loaddata *data) -diff --git a/security/apparmor/label.c b/security/apparmor/label.c -index c71e4615dd46..e8e5baaf05fa 100644 ---- a/security/apparmor/label.c -+++ b/security/apparmor/label.c -@@ -52,7 +52,8 @@ static void free_proxy(struct aa_proxy *proxy) - - void aa_proxy_kref(struct kref *kref) - { -- struct aa_proxy *proxy = container_of(kref, struct aa_proxy, count); -+ struct aa_proxy *proxy = container_of(kref, struct aa_proxy, -+ count.count); - - free_proxy(proxy); - } -@@ -63,7 +64,8 @@ struct aa_proxy *aa_alloc_proxy(struct aa_label *label, gfp_t gfp) - - new = kzalloc(sizeof(struct aa_proxy), gfp); - if (new) { -- kref_init(&new->count); -+ kref_init(&new->count.count); -+ new->count.reftype = REF_PROXY; - rcu_assign_pointer(new->label, aa_get_label(label)); - } - return new; -@@ -371,7 +373,8 @@ static void label_free_rcu(struct rcu_head *head) - - void aa_label_kref(struct kref *kref) - { -- struct aa_label *label = container_of(kref, struct aa_label, count); -+ struct aa_label *label = container_of(kref, struct aa_label, -+ count.count); - struct aa_ns *ns = labels_ns(label); - - if (!ns) { -@@ -408,7 +411,8 @@ bool aa_label_init(struct aa_label *label, int size, gfp_t gfp) - - label->size = size; /* doesn't include null */ - label->vec[size] = NULL; /* null terminate */ -- kref_init(&label->count); -+ kref_init(&label->count.count); -+ label->count.reftype = REF_NS; /* for aafs purposes */ - RB_CLEAR_NODE(&label->node); - - return true; -diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c -index 36175b99914b..b14ead4075ae 100644 ---- a/security/apparmor/policy_unpack.c -+++ b/security/apparmor/policy_unpack.c -@@ -118,7 +118,8 @@ static void do_loaddata_free(struct aa_loaddata *d) - - void aa_loaddata_kref(struct kref *kref) - { -- struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count); -+ struct aa_loaddata *d = container_of(kref, struct aa_loaddata, -+ count.count); - - do_loaddata_free(d); - } -@@ -165,7 +166,8 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size) - kfree(d); - return ERR_PTR(-ENOMEM); - } -- kref_init(&d->count); -+ kref_init(&d->count.count); -+ d->count.reftype = REF_RAWDATA; - kref_init(&d->pcount); - INIT_LIST_HEAD(&d->list); - --- -2.53.0 - diff --git a/patches-sonic/series b/patches-sonic/series index f293d14e3..9b4016aab 100644 --- a/patches-sonic/series +++ b/patches-sonic/series @@ -45,7 +45,8 @@ driver-net-tg3-change-dma-mask-for-57766.patch 0005-dt-bindings-hwmon-Add-tmp75b-to-lm75.txt.patch 0006-device-tree-bindinds-add-NXP-PCT2075-as-compatible-d.patch revert-acpi-osl-use-threaded-irq-for-sci.patch -platform-x86-int0002-remove-irqf-oneshot.patch +# Upstreamed in 6.12.94 (stable commit f6bc712877f2); backport is now a no-op. +#platform-x86-int0002-remove-irqf-oneshot.patch #Support-for-fullcone-nat.patch # TODO(trixie): update for current version # @@ -99,7 +100,7 @@ driver-i2c-smbus-add-disable_spd-module-parameter.patch 0027-platform-mellanox-mlx-platform-Change-register-name.patch 0028-platform-mellanox-mlxreg-dpu-Add-initial-support-for.patch 0029-platform-mellanox-Introduce-support-of-Nvidia-smart-.patch -0030-hwmon-mlxreg-fan-Separate-methods-of-fan-setting-com.patch +#0030-hwmon-mlxreg-fan-Separate-methods-of-fan-setting-com.patch 0031-platform-mellanox-indicate-deferred-I2C-bus-creation.patch 0032-platform_data-mlxreg-Add-capability-bit-and-mask-fie.patch 0033-platform-mellanox-mlxreg-hotplug-Add-support-for-new.patch @@ -116,7 +117,7 @@ driver-i2c-smbus-add-disable_spd-module-parameter.patch 0044-platform_data-mlxreg-Add-non-sticky-bit-indication-f.patch 0045-platform-mellanox-mlxreg-hotplug-Add-handling-of-non.patch 0046-platform-mellanox-nvsw-bmc-Add-system-control-and-mo.patch -0047-hwmon-mlxreg-fan-Prevent-fans-from-getting-stuck-at-.patch +#0047-hwmon-mlxreg-fan-Prevent-fans-from-getting-stuck-at-.patch 0052-platform-mellanox-Introduce-support-for-switches-equ.patch 0053-platform-mellanox-mlx-platform-Add-support-for-new-X.patch 0054-i2c-asf-Introduce-MCTP-support-over-ASF-controller.patch @@ -151,11 +152,9 @@ driver-i2c-smbus-add-disable_spd-module-parameter.patch # Cisco patches for 5.10 kernel cisco-mtd-part.patch cisco-mdio-mux-support-acpi.patch -#cisco-x86-gpio-config.patch # Deprecated, GPIOs are effectively unlimited cisco-acpi-spi-nor.patch cisco-Enable-static-memory-reservation-for-OIRable-PCIe-de.patch cisco-npu-disable-other-bars.patch -#cisco-hwmon-pmbus_core-pec-support-check.patch # Upstreamed 0001-regmap-i2c-add-SMBus-byte-word-reg16-bus-for-adapter.patch 0002-regmap-i2c-fix-sparse-warning-in-regmap_smbus_word_w.patch @@ -165,12 +164,7 @@ cisco-npu-disable-other-bars.patch # # Marvell platform patches for 6.1 kernel 0001-armhf_secondary_boot_online.patch -#0002-arm64-dts-Update-cache-properties-for-marvell.patch # Upstreamed -#0003-arm64-dts-marvell-Add-NAND-flash-controller-to-AC5.patch # Upstreamed -#0004-arm64-dts-ac5-add-mmc-node-and-clock.patch # Upstreamed 0005-dts-ac5-marvell-Add-switching-watchdog-node.patch -#0006-mmc-xenon-Add-ac5-support-via-bounce-buffer.patch # Upstreamed -#0007-usb-ehci-Add-support-for-ac5.patch # Upstreamed but no 64-bit, so the next 0007 0007-usb-ehci-Add-support-for-ac5-with-DMA-mask-64-bit.patch 0008-mv6xxx-Fix-i2c-lock-due-to-arb-loss.patch 0009-dt-bindings-marvell-Add-ARMADA-7K-properties.patch @@ -217,7 +211,7 @@ cisco-npu-disable-other-bars.patch 0027-pcie-if-hotplug-enabled-do-immediate-reset-on-panic.patch # amd sfh hid -0001-amd_sfh_hid_client_init_log_no_error_for_EOPNOTSUPP.patch +#0001-amd_sfh_hid_client_init_log_no_error_for_EOPNOTSUPP.patch # Security patch #0001-Change-the-system.map-file-permission-only-readable-.patch @@ -233,7 +227,7 @@ cisco-npu-disable-other-bars.patch 0004-xilinx-spi-platform_get_irq_optional.patch 0005-xilinx-spi-use-device-property.patch driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pending -0001-PM-runtime-Add-new-devm-functions.patch +#0001-PM-runtime-Add-new-devm-functions.patch 0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch 0008-i2c-xiic-Add-atomic-transfer-support.patch 0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch @@ -247,10 +241,6 @@ driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pen 0017-dt-bindings-trivial-devices-Add-Delta-Q54SN120A1-and-Q54SW120A7.patch 0018-hwmon-pmbus-Add-Delta-Q54SN120A1-Q54SW120A7-chip.patch -# Fix to avoid kernel panic on Kernel 6.1.94 -# https://github.com/sonic-net/sonic-buildimage/issues/20901 -#PCI-ASPM-Fix-link-state-exit-during-switch-upstream.patch # Upstreamed - # 0001-PCI-AER-Simplify-pci_print_aer.patch 0002-PCI-AER-Update-statistics-before-ratelimiting.patch @@ -265,18 +255,6 @@ driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pen 0011-PCI-AER-Fix-NULL-pointer-access-by-aer_info.patch 0012-PCI-AER-Avoid-NULL-pointer-dereference-in-aer_rateli.patch -# QID-45097: Crackarmor fixes -qsa-2026-apparmor/0001-apparmor-validate-DFA-start-states-are-in-bounds-in-.patch -qsa-2026-apparmor/0002-apparmor-fix-memory-leak-in-verify_header.patch -qsa-2026-apparmor/0003-apparmor-replace-recursive-profile-removal-with-iter.patch -qsa-2026-apparmor/0004-apparmor-fix-limit-the-number-of-levels-of-policy-na.patch -qsa-2026-apparmor/0005-apparmor-fix-side-effect-bug-in-match_char-macro-usa.patch -qsa-2026-apparmor/0006-apparmor-fix-missing-bounds-check-on-DEFAULT-table-i.patch -qsa-2026-apparmor/0007-apparmor-Fix-double-free-of-ns_name-in-aa_replace_pr.patch -qsa-2026-apparmor/0008-apparmor-fix-unprivileged-local-user-can-do-privileg.patch -qsa-2026-apparmor/0009-apparmor-fix-differential-encoding-verification.patch -qsa-2026-apparmor/0010-apparmor-fix-race-on-rawdata-dereference.patch -qsa-2026-apparmor/0011-apparmor-fix-race-between-freeing-data-and-fs-access.patch # Patches for EVPN MH 0001-vxlan-bridge-Add-NDA_FLAGS_EXT-support-with-NTF_EXT_.patch 0002-net-bridge-vxlan-Protocol-field-in-bridge-fdb.patch @@ -290,11 +268,15 @@ qsa-2026-apparmor/0011-apparmor-fix-race-between-freeing-data-and-fs-access.patc ############################################################ ###-> aspeed ###-> aspeed-upstream +# Full regen against pristine 6.12.94 at Aspeed tag v00.07.04, split three ways: +# 0001 - all Aspeed-namespace files (new + updated) +# 0002 - new non-Aspeed dependency subsystems (i3c/mctp, jtag, dwc trng, ...) +# 0003 - modifications to shared/common kernel files (review surface) +# The mmc-sdhci-of-aspeed CMD6-timing and tuning backports are subsumed by +# v00.07.04 (folded into 0001), so they are no longer carried separately. 0001-aspeed-ast2700-support.patch -0002-aspeed-ast2700-aspeed-new-files-update-to-6.12-00.07.02.patch -0003-aspeed-ast2700-aspeed-diff-vendor-independent-changes-update-to-6.12-00.07.02.patch -mmc-sdhci-of-aspeed-Improve-CMD6-timing_v6.18.patch -mmc-sdhci-of-aspeed-Optimize-tuning-mechanism_v6.12.patch +0002-aspeed-ast2700-non-aspeed-deps-update-to-6.12.94-00.07.04.patch +0003-aspeed-ast2700-shared-kernel-changes-update-to-6.12.94-00.07.04.patch ###-> aspeed-upstream-end aspeed-spi-txrx-fix-full-duplex-capture.patch nexthop-b27-dts.patch @@ -308,18 +290,18 @@ micas-m2-w6950-128oc-dts.patch ###-> aspeed-end ###-> nvidia_aspeed_bmc-start -0001-mctp-driver-net-Extend-MCTP-support.patch -0002-mctp-aspeed-IRoT-Add-initial-support.patch -0003-mctp-driver-net-Add-global-APIs-for-MCTP.patch -0004-mctp-driver-net-Fix-MCTP-over-VDM-PCIe.patch -0005-mctp-driver-net-Fix-MCTP-over-USB.patch -0006-jtag-Add-JTAG-core-headers-GPIO-mux-and-locking-support.patch -0007-JTAG-Aspeed-Fix-kernel-configuration.patch -0008-arm64-dts-aspeed-spc6-bmc-ext-phram-env-tpm-i3c-pull.patch -0009-arm64-dts-aspeed-split-SPC6-BMC-DTS-for-SONiC-and-Op.patch -0010-net-ftgmac100-hard-reset-mac-for-sgmii.patch -0011-arm64-dts-aspeed-spc6-bmc-fix-sgmii-phy-names.patch -0012-usb-ehci-Add-Aspeed-AST2700-support.patch +#0001-mctp-driver-net-Extend-MCTP-support.patch +#0002-mctp-aspeed-IRoT-Add-initial-support.patch +#0003-mctp-driver-net-Add-global-APIs-for-MCTP.patch +#0004-mctp-driver-net-Fix-MCTP-over-VDM-PCIe.patch +#0005-mctp-driver-net-Fix-MCTP-over-USB.patch +#0006-jtag-Add-JTAG-core-headers-GPIO-mux-and-locking-support.patch +#0007-JTAG-Aspeed-Fix-kernel-configuration.patch +#0008-arm64-dts-aspeed-spc6-bmc-ext-phram-env-tpm-i3c-pull.patch +#0009-arm64-dts-aspeed-split-SPC6-BMC-DTS-for-SONiC-and-Op.patch +#0010-net-ftgmac100-hard-reset-mac-for-sgmii.patch +#0011-arm64-dts-aspeed-spc6-bmc-fix-sgmii-phy-names.patch +#0012-usb-ehci-Add-Aspeed-AST2700-support.patch ###-> nvidia_aspeed_bmc-end # diff --git a/scripts/aspeed_content_scan.py b/scripts/aspeed_content_scan.py new file mode 100644 index 000000000..91f4448f3 --- /dev/null +++ b/scripts/aspeed_content_scan.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +"""Scan a file or directory for keyword matches, ignoring comments. + +Used by generate-aspeed-patch.sh to decide whether a new file/directory is +genuinely Aspeed-related. A plain `grep -ri aspeed` also matches attribution +comments such as "Based on aspeed-socinfo.c", which pulls in unrelated files +(e.g. drivers/soc/vt8500). This helper strips comments before matching so that +only real code/config references count. + +Usage: + aspeed_content_scan.py [regex] + +Exit status: + 0 - at least one non-comment match found + 1 - no non-comment match found (or path missing) +""" + +import os +import re +import sys + +DEFAULT_REGEX = r"aspeed|ast2[567]00|ast1[78]00" + +# Extensions / filenames that use C-style comments (/* */ and //). +C_STYLE_EXT = {".c", ".h", ".dts", ".dtsi", ".dtso", ".S", ".s"} +# Extensions / filenames that use hash (#) comments. +HASH_STYLE_EXT = {".yaml", ".yml", ".txt", ".rst", ".mk", ".defconfig", + ".config", ".sh", ".py"} +HASH_STYLE_NAMES = {"Kconfig", "Makefile", "Kbuild"} + +_C_BLOCK = re.compile(r"/\*.*?\*/", re.DOTALL) +_C_LINE = re.compile(r"//[^\n]*") +_HASH_LINE = re.compile(r"#[^\n]*") + + +def _strip_c_comments(text): + text = _C_BLOCK.sub(" ", text) + text = _C_LINE.sub(" ", text) + return text + + +def _strip_hash_comments(text): + return _HASH_LINE.sub(" ", text) + + +def _style_for(path): + base = os.path.basename(path) + if base in HASH_STYLE_NAMES or base.startswith("Kconfig") or \ + base.startswith("Makefile"): + return "hash" + ext = os.path.splitext(base)[1] + if ext in C_STYLE_EXT: + return "c" + if ext in HASH_STYLE_EXT: + return "hash" + # Unknown: strip C-style only. This is the safe default because stripping + # '#' from an unknown C-like file would remove #include/#define lines that + # may legitimately reference an aspeed header. + return "c" + + +def _strip_comments(path, text): + style = _style_for(path) + if style == "hash": + return _strip_hash_comments(text) + return _strip_c_comments(text) + + +def _file_matches(path, pattern): + try: + with open(path, "r", encoding="utf-8", errors="ignore") as fh: + text = fh.read() + except (OSError, IOError): + return False + stripped = _strip_comments(path, text) + return pattern.search(stripped) is not None + + +def main(argv): + if len(argv) < 2: + sys.stderr.write("usage: aspeed_content_scan.py [regex]\n") + return 2 + target = argv[1] + regex = argv[2] if len(argv) > 2 else DEFAULT_REGEX + pattern = re.compile(regex, re.IGNORECASE) + + if os.path.isfile(target): + return 0 if _file_matches(target, pattern) else 1 + + if os.path.isdir(target): + for root, _dirs, files in os.walk(target): + for name in files: + if _file_matches(os.path.join(root, name), pattern): + return 0 + return 1 + + return 1 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/scripts/generate-aspeed-patch.sh b/scripts/generate-aspeed-patch.sh index b3d657999..4bc0cf283 100755 --- a/scripts/generate-aspeed-patch.sh +++ b/scripts/generate-aspeed-patch.sh @@ -1,9 +1,20 @@ #!/bin/bash -# Generates an incremental Aspeed AST2700 patch for the SONiC kernel. -# Diffs (kernel with all currently-committed series patches applied) against -# (kernel with a fresh Aspeed upstream merge). The output captures whatever -# is new in upstream relative to the existing patches-sonic/ series. See the -# design comment further below for details. +# Generates an Aspeed AST2700 patch for the SONiC kernel. Two modes: +# +# incremental (default): diffs (kernel + all currently-committed series +# patches) against (kernel + a fresh Aspeed upstream merge). The output +# captures whatever a newer Aspeed tag adds on top of the existing +# patches-sonic/ series. Use for routine Aspeed tag bumps while the SONiC +# kernel version is unchanged. +# +# baseline (--baseline): diffs pristine sonic-src (the committed +# ###-> aspeed-upstream patches are NOT applied) against a fresh Aspeed +# merge, yielding the FULL Aspeed support for the current SONiC kernel. +# Use to reset the baseline when the SONiC kernel version itself changes, +# then feed the result to split-aspeed-patch.py to regenerate the +# 0001/0002/0003 patch set. +# +# See the design comment further below for details. set -e @@ -11,21 +22,92 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" KERNEL_DIR="$(dirname "$SCRIPT_DIR")" BUILD_DIR="$(dirname "$(dirname "$KERNEL_DIR")")" +# Mode selection (see the header comment for the full description): +# (default) incremental - baseline tree includes the committed +# ###-> aspeed-upstream patches; output is the delta only. +# --baseline baseline reset - baseline tree is pristine sonic-src; output is +# the full Aspeed support. Pair with split-aspeed-patch.py when +# the SONiC kernel version changes. +BASELINE_MODE=0 +usage() { + cat <] $0 [--baseline] + + --baseline Generate the full baseline patch: do NOT apply the committed + ###-> aspeed-upstream patches to the baseline tree. Use when the + SONiC kernel version changes, then split the result with + scripts/split-aspeed-patch.py to regenerate 0001/0002/0003. + -h, --help Show this help and exit. + +Without --baseline the script produces an incremental patch: the delta between +the currently-committed series state and a fresh Aspeed upstream merge. +EOF +} +while [ $# -gt 0 ]; do + case "$1" in + --baseline) BASELINE_MODE=1 ;; + -h|--help) usage; exit 0 ;; + *) echo "Unknown argument: $1" >&2; usage; exit 1 ;; + esac + shift +done + # Configuration -# Example, run with ASPEED_TAG=v00.07.02 ./scripts/generate-aspeed-patch.sh -ASPEED_REF="${ASPEED_TAG:-aspeed-master-v6.12}" +# By default the script auto-detects the latest Aspeed release tag on the kernel +# line that matches the SONiC kernel (e.g. 6.12 -> aspeed-master-v6.12). To pin a +# specific ref, override it explicitly: +# ASPEED_TAG=v00.07.04 ./scripts/generate-aspeed-patch.sh ASPEED_REPO="https://github.com/AspeedTech-BMC/linux.git" WORK_DIR="${TMPDIR:-/tmp}/aspeed-patch-gen" ASPEED_SRC="$WORK_DIR/aspeed-src" SONIC_SRC="$WORK_DIR/sonic-src" BASELINE_TREE="$WORK_DIR/baseline" SONIC_ASPEED="$WORK_DIR/sonic-src-aspeed" -OUTPUT_PATCH="$WORK_DIR/aspeed-ast2700-incremental.patch" +# AST2700 (g7) defconfig. Used by Step 5c2 to decide whether a genuinely-new +# source directory is actually needed by the Aspeed image (dual-gate: content +# scan OR defconfig membership). +ASPEED_DEFCONFIG="$ASPEED_SRC/arch/arm64/configs/aspeed_g7_defconfig" +if [ "$BASELINE_MODE" -eq 1 ]; then + OUTPUT_PATCH="$WORK_DIR/aspeed-ast2700-baseline.patch" +else + OUTPUT_PATCH="$WORK_DIR/aspeed-ast2700-incremental.patch" +fi # Read kernel version from Makefile KERNEL_VERSION=$(sed -nE 's/^KERNEL_VERSION[[:space:]]*[?:+]?=[[:space:]]*//p' "$KERNEL_DIR/Makefile") SONIC_KERNEL_URL="https://packages.trafficmanager.net/public/debian-security/pool/updates/main/l/linux/linux_${KERNEL_VERSION}.orig.tar.xz" +# Derive the Aspeed kernel-line branch from the SONiC kernel version (e.g. 6.12). +ASPEED_KERNEL_LINE=$(printf '%s' "$KERNEL_VERSION" | grep -oE '^[0-9]+\.[0-9]+') +ASPEED_LINE_BRANCH="aspeed-master-v${ASPEED_KERNEL_LINE}" + +# Resolve which ref to use. An explicit ASPEED_TAG always wins; otherwise find +# the latest release tag published at the tip of the matching kernel line. +# Aspeed tags releases at the tip of each aspeed-master-v branch, so we +# match tags by the branch-tip commit and pick the highest version when several +# point at the same commit. +if [ -n "$ASPEED_TAG" ]; then + ASPEED_REF="$ASPEED_TAG" + echo "Using explicitly requested Aspeed ref: $ASPEED_REF" +else + echo "Resolving latest Aspeed release tag on '$ASPEED_LINE_BRANCH'..." + LINE_TIP=$(git ls-remote "$ASPEED_REPO" "refs/heads/$ASPEED_LINE_BRANCH" 2>/dev/null | awk 'END{print $1}') + LATEST_TAG="" + if [ -n "$LINE_TIP" ]; then + LATEST_TAG=$(git ls-remote --tags "$ASPEED_REPO" 2>/dev/null \ + | awk -v tip="$LINE_TIP" '$1==tip {print $2}' \ + | sed -e 's,refs/tags/,,' -e 's,\^{},,' \ + | sort -u | sort -V | tail -n1) + fi + if [ -n "$LATEST_TAG" ]; then + echo " Latest tag for ${ASPEED_KERNEL_LINE}: $LATEST_TAG (branch tip $LINE_TIP)" + ASPEED_REF="$LATEST_TAG" + else + echo " No release tag found at tip of '$ASPEED_LINE_BRANCH'; falling back to the branch." + ASPEED_REF="$ASPEED_LINE_BRANCH" + fi +fi + # Patch author for the generated From:/Signed-off-by: lines. Resolution order: # 1. $PATCH_AUTHOR if provided ("Name ") # 2. the invoking user's git identity (git config user.name/user.email) @@ -45,7 +127,11 @@ fi TOTAL_APPLY_FAILURES=0 echo "=========================================" +if [ "$BASELINE_MODE" -eq 1 ]; then +echo "Aspeed Patch Generation Script (baseline / full)" +else echo "Aspeed Patch Generation Script (incremental)" +fi echo "=========================================" echo "Kernel Version: $KERNEL_VERSION" echo "Aspeed Upstream Ref: $ASPEED_REF" @@ -72,17 +158,22 @@ fi echo "" echo "Step 1: Downloading Aspeed kernel source..." if [ -d "$ASPEED_SRC/.git" ]; then - cached_branch=$(git -C "$ASPEED_SRC" rev-parse --abbrev-ref HEAD 2>/dev/null) - head_commit=$(git -C "$ASPEED_SRC" rev-parse -q --verify HEAD 2>/dev/null) - ref_commit=$(git -C "$ASPEED_SRC" rev-parse -q --verify "${ASPEED_REF}^{commit}" 2>/dev/null) - if [ "$cached_branch" = "$ASPEED_REF" ] || { [ -n "$head_commit" ] && [ "$head_commit" = "$ref_commit" ]; }; then - echo "Aspeed source already exists at $ASPEED_SRC and is at $ASPEED_REF, reusing" + echo "Aspeed source already exists; verifying it matches '$ASPEED_REF'..." + # Resolve the requested ref (branch or annotated/lightweight tag) on the + # remote. For an annotated tag the peeled "^{}" line carries the commit; + # take the last matching line so we always compare against the commit a + # checkout would land on. Auto-tag detection can resolve to a newer tag + # than a cached tree, so re-fetch rather than silently reuse stale content. + want_sha=$(git ls-remote "$ASPEED_REPO" "$ASPEED_REF" "refs/tags/$ASPEED_REF^{}" 2>/dev/null | awk 'END{print $1}') + have_sha=$(git -C "$ASPEED_SRC" rev-parse HEAD 2>/dev/null) + if [ -n "$want_sha" ] && [ "$want_sha" != "$have_sha" ]; then + echo " Cached tree is at ${have_sha:-} but '$ASPEED_REF' is $want_sha; re-fetching..." + git -C "$ASPEED_SRC" fetch --depth 1 "$ASPEED_REPO" "$ASPEED_REF" + git -C "$ASPEED_SRC" checkout --quiet --detach FETCH_HEAD + git -C "$ASPEED_SRC" reset --hard --quiet FETCH_HEAD + git -C "$ASPEED_SRC" clean -fdxq else - echo " WARNING: cached Aspeed source at $ASPEED_SRC is NOT at $ASPEED_REF" - echo " WARNING: checked out: ${cached_branch:-} ($head_commit)" - echo " WARNING: expected: $ASPEED_REF" - echo " WARNING: reusing it as-is — the generated diff may not reflect $ASPEED_REF." - echo " WARNING: remove $ASPEED_SRC and re-run to force a fresh clone." + echo "Aspeed source already exists at $ASPEED_SRC and is at $ASPEED_REF, reusing" fi else rm -rf "$ASPEED_SRC" @@ -315,10 +406,15 @@ echo "" echo "Step 3: Applying non-Aspeed SONiC patches into sonic-src..." apply_patches "$SONIC_SRC" "non-aspeed" "sonic-src (shared base)" -# Step 3b: Build baseline tree = sonic-src + the ###-> aspeed-upstream patches. -# Represents the committed upstream-merge state the incremental will diff -# against. Hand-written aspeed-section patches are intentionally skipped (they -# cancel by absence — they're applied to neither tree). +# Step 3b: Build the baseline tree the output diff is taken against. +# incremental mode: sonic-src + the committed ###-> aspeed-upstream patches +# (the current committed upstream-merge state, so the diff +# captures only what a newer Aspeed tag adds). +# baseline mode : pristine sonic-src only (the aspeed-upstream patches are +# NOT applied), so the diff is the FULL Aspeed support for a +# SONiC kernel baseline reset. +# Hand-written aspeed-section patches are intentionally skipped in both modes +# (they cancel by absence — they're applied to neither tree). echo "" echo "Step 3b: Building baseline tree..." if [ -d "$BASELINE_TREE" ]; then @@ -326,7 +422,11 @@ if [ -d "$BASELINE_TREE" ]; then rm -rf "$BASELINE_TREE" fi cp -a "$SONIC_SRC" "$BASELINE_TREE" -apply_patches "$BASELINE_TREE" "aspeed-upstream" "baseline" +if [ "$BASELINE_MODE" -eq 1 ]; then + echo " baseline mode: NOT applying ###-> aspeed-upstream patches (full patch)" +else + apply_patches "$BASELINE_TREE" "aspeed-upstream" "baseline" +fi echo "Baseline tree ready: $(du -sh $BASELINE_TREE | cut -f1)" # Steps 4 + 5: build the target tree by merging fresh Aspeed upstream content @@ -510,19 +610,56 @@ while IFS= read -r aspeed_kconfig; do source_file="$ASPEED_SRC/$source_path" source_dir=$(dirname "$source_file") - # Check if the source directory exists and contains Aspeed-related content + # Check if the source directory exists if [ -d "$source_dir" ]; then - set +e - # Check if directory or its Kconfig has Aspeed references - grep -rqi "aspeed\|ast2[567]00\|ast1[78]00" "$source_dir" 2>/dev/null - if [ $? -eq 0 ]; then - rel_source_dir="${source_dir#$ASPEED_SRC/}" - echo " Found new source directory: $rel_source_dir" - mkdir -p "$SONIC_ASPEED/$rel_source_dir" - cp -rv "$source_dir/"* "$SONIC_ASPEED/$rel_source_dir/" | wc -l - KCONFIG_DIR_COUNT=$((KCONFIG_DIR_COUNT + 1)) + rel_source_dir="${source_dir#$ASPEED_SRC/}" + # Only copy directories that are genuinely NEW (absent from the + # SONiC base). A new +source statement can reference a sibling + # Kconfig file inside a pre-existing shared directory (e.g. the + # Aspeed tree adds `source "drivers/gpu/drm/Kconfig.debug"`), in + # which case dirname resolves to a large shared directory such as + # drivers/gpu/drm. Wholesale-copying that newer-kernel directory + # clobbers unrelated files and drops non-Aspeed obj-/subdir-y + # entries. Such shared directories are handled by the smart-merge + # steps (5b/5c) and the targeted file copies (5d), so skip them here. + if [ -d "$SONIC_SRC/$rel_source_dir" ]; then + echo " Skipping pre-existing shared directory: $rel_source_dir (handled by smart merge / targeted copy)" + else + # Genuinely new directory (absent from the SONiC base) + # referenced by a new +source statement. "New to SONiC" + # is NOT the same as "Aspeed addition": the SONiC/Debian + # tree strips many vanilla drivers (e.g. staging/rtl8712) + # that the near-vanilla Aspeed tree still carries. Only + # bring the directory in if it is genuinely Aspeed-relevant: + # (a) its code/config references Aspeed (content scan), or + # (b) a Kconfig symbol it defines is enabled in the Aspeed + # g7 defconfig -- this catches Intel-authored but + # Aspeed-required stacks like drivers/i3c/mctp + # (CONFIG_I3C_MCTP=y) whose code carries no "aspeed" + # marker. + set +e + python3 "$SCRIPT_DIR/aspeed_content_scan.py" "$source_dir" 2>/dev/null + wanted=$? + if [ $wanted -ne 0 ] && [ -f "$ASPEED_DEFCONFIG" ]; then + dir_syms=$(grep -hoE '^[[:space:]]*(menu)?config [A-Z0-9_]+' "$source_dir/Kconfig" 2>/dev/null | awk '{print $NF}') + for sym in $dir_syms; do + if grep -qE "^CONFIG_${sym}=(y|m)\$" "$ASPEED_DEFCONFIG"; then + wanted=0 + break + fi + done + fi + set -e + + if [ $wanted -eq 0 ]; then + echo " Found new source directory: $rel_source_dir" + mkdir -p "$SONIC_ASPEED/$rel_source_dir" + cp -rv "$source_dir/"* "$SONIC_ASPEED/$rel_source_dir/" | wc -l + KCONFIG_DIR_COUNT=$((KCONFIG_DIR_COUNT + 1)) + else + echo " Skipping new non-Aspeed directory: $rel_source_dir (no Aspeed content, not enabled by aspeed_g7_defconfig)" + fi fi - set -e fi fi done <<< "$new_sources" @@ -851,6 +988,21 @@ echo "Converted to git format: $(du -sh $WORK_DIR/aspeed-changes-git.diff | cut # Step 8: Create git patch with header echo "" echo "Step 8: Creating git patch with header..." +if [ "$BASELINE_MODE" -eq 1 ]; then +cat > "$OUTPUT_PATCH" << PATCH_HEADER +From: ${PATCH_AUTHOR} +Date: $(date -R) +Subject: [PATCH] Aspeed AST2700 full support (baseline for ${KERNEL_VERSION}) + +Full Aspeed AST2700 support generated against the pristine ${KERNEL_VERSION} +SONiC kernel at Aspeed ${ASPEED_REF}. Baseline reset: the committed +###-> aspeed-upstream patches were NOT applied. Split with split-aspeed-patch.py +into 0001/0002/0003 to replace the currently-committed Aspeed support set. + +Signed-off-by: ${PATCH_AUTHOR} +--- +PATCH_HEADER +else cat > "$OUTPUT_PATCH" << PATCH_HEADER From: ${PATCH_AUTHOR} Date: $(date -R) @@ -865,6 +1017,7 @@ sub-section in patches-sonic/series (after the prior upstream patches, before Signed-off-by: ${PATCH_AUTHOR} --- PATCH_HEADER +fi cat "$WORK_DIR/aspeed-changes-git.diff" >> "$OUTPUT_PATCH" echo "Git patch created: $(du -sh $OUTPUT_PATCH | cut -f1)" @@ -883,6 +1036,85 @@ echo "Sample of changed files:" grep '^diff --git' "$OUTPUT_PATCH" | head -20 echo "" +# Step 10: Sanity check for non-Aspeed deletions +echo "=========================================" +echo "Step 10: Sanity Check for Non-Aspeed Deletions" +echo "=========================================" +echo "Scanning patch for suspicious deletions in Kconfig/Makefile files..." +echo "" + +SUSPICIOUS_DELETIONS_FOUND=0 + +# Check for deletions in Kconfig files (config entries) +echo "Checking Kconfig deletions..." +KCONFIG_DELETIONS=$(grep -B2 "^-config " "$OUTPUT_PATCH" | grep -v "^--$" | grep "^diff.*Kconfig" || true) + +if [ -n "$KCONFIG_DELETIONS" ]; then + echo "⚠️ WARNING: Found config deletions in Kconfig files:" + grep -B1 -A5 "^-config " "$OUTPUT_PATCH" | grep -v "aspeed\|ast2[567]00\|ast1[78]00" | head -50 + SUSPICIOUS_DELETIONS_FOUND=1 + echo "" +fi + +# Check for deletions in Makefile files (obj- entries) +echo "Checking Makefile deletions..." +MAKEFILE_OBJ_DELETIONS=$(grep "^-obj-\|^-subdir-y" "$OUTPUT_PATCH" | grep -v "aspeed\|ast2[567]00\|ast1[78]00" || true) + +if [ -n "$MAKEFILE_OBJ_DELETIONS" ]; then + echo "⚠️ WARNING: Found non-Aspeed obj/subdir deletions in Makefile files:" + echo "$MAKEFILE_OBJ_DELETIONS" | head -50 + SUSPICIOUS_DELETIONS_FOUND=1 + echo "" + + # Show specific problematic patterns + echo "Known problematic deletions to review:" + grep "^-.*pensando\|^-.*elba\|^-.*IRQ_PENSANDO\|^-.*EDAC_ELBA\|^-.*RESET_ELBASR\|^-.*STM32MP_EXTI\|^-.*I2C_RD1173" "$OUTPUT_PATCH" || echo " (None of the known problematic patterns found)" + echo "" +fi + +# Check for deletions in arch/arm64/boot/dts/Makefile specifically +echo "Checking arch/arm64/boot/dts/Makefile deletions..." +AARCH64_DTS_DELETIONS=$(grep -A20 "^diff.*arch/arm64/boot/dts/Makefile" "$OUTPUT_PATCH" | grep "^-subdir-y" | grep -v "aspeed" || true) + +if [ -n "$AARCH64_DTS_DELETIONS" ]; then + echo "⚠️ WARNING: Found subdirectory deletions in arch/arm64/boot/dts/Makefile:" + echo "$AARCH64_DTS_DELETIONS" + SUSPICIOUS_DELETIONS_FOUND=1 + echo "" +fi + +# Summary +echo "=========================================" +if [ $SUSPICIOUS_DELETIONS_FOUND -eq 1 ]; then + echo "❌ SANITY CHECK FAILED!" + echo "Found suspicious non-Aspeed deletions in the patch." + echo "Please review the patch carefully before applying." + echo "Look for deletions of:" + echo " - config entries (pensando, elba, etc.)" + echo " - Makefile obj- entries" + echo " - subdir-y entries" + echo "" + echo "To review deletions:" + echo " grep '^-config ' $OUTPUT_PATCH | grep -v aspeed" + echo " grep '^-obj-\\|^-subdir-y' $OUTPUT_PATCH | grep -v aspeed" +else + echo "✅ SANITY CHECK PASSED!" + echo "No suspicious non-Aspeed deletions found." +fi +echo "=========================================" +echo "" + +if [ "$BASELINE_MODE" -eq 1 ]; then +echo "To stage the baseline patch set (SONiC kernel version reset):" +echo " # 1. Split the full patch into the Rule-B 3-part set, writing directly" +echo " # into patches-sonic/ (replaces the prior 0001/0002/0003):" +echo " INPUT_PATCH=$OUTPUT_PATCH ASPEED_REF=$ASPEED_REF \\" +echo " OUTDIR=$KERNEL_DIR/patches-sonic $SCRIPT_DIR/split-aspeed-patch.py" +echo "" +echo " # 2. Refresh the ###-> aspeed-upstream block in patches-sonic/series so" +echo " # it lists the regenerated 0001/0002/0003 files, then re-run this" +echo " # script without --baseline to confirm the incremental delta is empty." +else echo "To stage the incremental patch:" echo " # 1. Rename to reflect what the bump represents, e.g." echo " # aspeed-ast2700-v00.07.02-to-v00.07.03.patch" @@ -901,5 +1133,6 @@ echo " # .patch <-- new" echo " # ###-> aspeed-upstream-end" echo " # -board-dts.patch" echo " # ###-> aspeed-end" +fi echo "" diff --git a/scripts/split-aspeed-patch.py b/scripts/split-aspeed-patch.py new file mode 100755 index 000000000..5f8fde14f --- /dev/null +++ b/scripts/split-aspeed-patch.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# Splits the monolithic Aspeed incremental patch produced by +# generate-aspeed-patch.sh into the Rule-B 3-part set. Intended as the +# post-generation step of a baseline reset (SONiC kernel version bump), where a +# fresh full merge replaces 0001/0002/0003 rather than appending an increment. +# +# Rule B (per changed file): +# 0001 - anything under the Aspeed namespace (path matches aspeed/astNN00), +# both new files and modifications to Aspeed drivers already upstream. +# 0002 - brand-new files outside the Aspeed namespace (self-contained +# dependency subsystems, e.g. i3c/mctp, jtag, dwc trng). +# 0003 - modifications to existing shared/common kernel files (the +# vendor-independent review surface, e.g. pwm/core.c, Kconfig merges). +# +# All configuration mirrors generate-aspeed-patch.sh and is overridable via the +# environment so the two scripts share one source of truth: +# INPUT_PATCH, WORK_DIR, OUTDIR, KERNEL_VERSION, ASPEED_REF/ASPEED_TAG, +# PATCH_AUTHOR, PATCH_DATE +import os +import re +import subprocess +import sys +from email.utils import formatdate + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +KERNEL_DIR = os.path.dirname(SCRIPT_DIR) + +ASPEED_RE = re.compile(r"aspeed|ast1[0-9]00|ast2[0-9]00", re.I) + + +def _git_config(key): + try: + out = subprocess.run(["git", "-C", KERNEL_DIR, "config", key], + capture_output=True, text=True, check=False) + return out.stdout.strip() + except OSError: + return "" + + +def _kernel_version(): + v = os.environ.get("KERNEL_VERSION", "").strip() + if v: + return v + mk = os.path.join(KERNEL_DIR, "Makefile") + with open(mk, "r", errors="surrogateescape") as fh: + for line in fh: + m = re.match(r"^KERNEL_VERSION[ \t]*[?:+]?=[ \t]*(.+?)[ \t]*$", line) + if m: + return m.group(1).strip() + return "unknown" + + +def _author(): + a = os.environ.get("PATCH_AUTHOR", "").strip() + if a: + return a + name, email = _git_config("user.name"), _git_config("user.email") + if name and email: + return f"{name} <{email}>" + sys.exit("ERROR: no PATCH_AUTHOR and git user.name/user.email unset") + + +def _config(): + work = os.environ.get("WORK_DIR") or os.path.join( + os.environ.get("TMPDIR", "/tmp"), "aspeed-patch-gen") + ref = (os.environ.get("ASPEED_REF") or os.environ.get("ASPEED_TAG") or "").strip() + if not ref: + ref = "unknown-ref" + sys.stderr.write("WARNING: ASPEED_REF/ASPEED_TAG unset; using 'unknown-ref'\n") + return { + "src": os.environ.get("INPUT_PATCH") or os.path.join( + work, "aspeed-ast2700-incremental.patch"), + "outdir": os.environ.get("OUTDIR") or os.path.join(work, "aspeed-split"), + "kver": _kernel_version(), + "ref": ref, + "sfx": ref.lstrip("v"), + "author": _author(), + "date": os.environ.get("PATCH_DATE") or formatdate(localtime=True), + } + + +def _buckets(cfg): + kver, sfx, ref = cfg["kver"], cfg["sfx"], cfg["ref"] + return { + "0001": { + "file": f"{cfg['outdir']}/0001-aspeed-ast2700-support.patch", + "subject": "Aspeed AST2700 support: Aspeed-namespace files (new and updated)", + "body": ("All files under the Aspeed namespace (new files plus updates to\n" + "Aspeed drivers already present upstream), from a fresh Aspeed\n" + f"merge at {ref} on the {kver} SONiC kernel."), + "lines": [], + }, + "0002": { + "file": f"{cfg['outdir']}/0002-aspeed-ast2700-non-aspeed-deps-update-to-{kver}-{sfx}.patch", + "subject": "Aspeed AST2700 support: new non-Aspeed dependency subsystems", + "body": ("New, self-contained non-Aspeed subsystems the Aspeed image depends\n" + "on (i3c/mctp, jtag, dwc TRNG, mctp-pcie-vdm, xdma trace), from a\n" + f"fresh Aspeed merge at {ref} on the {kver} SONiC kernel."), + "lines": [], + }, + "0003": { + "file": f"{cfg['outdir']}/0003-aspeed-ast2700-shared-kernel-changes-update-to-{kver}-{sfx}.patch", + "subject": "Aspeed AST2700 support: modifications to shared/common kernel files", + "body": ("Modifications to existing vendor-independent (shared/common) kernel\n" + "files - the common-code review surface (Kconfig/Makefile merges,\n" + "ftgmac100, pwm/core, clk-provider, pwm.h, videodev2.h), from a\n" + f"fresh Aspeed merge at {ref} on the {kver} SONiC kernel."), + "lines": [], + }, + } + + +def _header(cfg, b): + return (f"From: {cfg['author']}\n" + f"Date: {cfg['date']}\n" + f"Subject: [PATCH] {b['subject']}\n\n" + f"{b['body']}\n\n" + f"Signed-off-by: {cfg['author']}\n" + "---\n") + + +def _classify(path, is_new): + if ASPEED_RE.search(path): + return "0001" + return "0002" if is_new else "0003" + + +def main(): + cfg = _config() + if not os.path.isfile(cfg["src"]): + sys.exit(f"ERROR: input patch not found: {cfg['src']}") + os.makedirs(cfg["outdir"], exist_ok=True) + buckets = _buckets(cfg) + with open(cfg["src"], "r", errors="surrogateescape") as fh: + lines = fh.readlines() + start = next((i for i, l in enumerate(lines) if l.startswith("diff --git ")), None) + if start is None: + sys.exit(f"ERROR: no 'diff --git' blocks found in {cfg['src']}") + blocks, cur = [], None + for l in lines[start:]: + if l.startswith("diff --git "): + if cur is not None: + blocks.append(cur) + cur = [l] + else: + cur.append(l) + if cur is not None: + blocks.append(cur) + counts = {"0001": 0, "0002": 0, "0003": 0} + for blk in blocks: + path = re.match(r"diff --git a/(.*?) b/", blk[0]).group(1) + is_new = next((x for x in blk if x.startswith("@@ ")), "").startswith("@@ -0,0") + key = _classify(path, is_new) + buckets[key]["lines"].extend(blk) + counts[key] += 1 + for key, b in buckets.items(): + with open(b["file"], "w", errors="surrogateescape") as out: + out.write(_header(cfg, b)) + out.writelines(b["lines"]) + print(f"{key}: {counts[key]:3d} files -> {b['file']}") + print(f"TOTAL: {sum(counts.values())} files") + print(f"\nCopy the three files into {KERNEL_DIR}/patches-sonic/ and refresh the\n" + "###-> aspeed-upstream block in patches-sonic/series.") + + +if __name__ == "__main__": + main()